java 非常好用的反射框架Reflections介绍
作者:wei906 发布时间:2022-11-25 01:25:52
Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据。
使用Reflections可以很轻松的获取以下元数据信息:
1)获取某个类型的所有子类;比如,有一个父类是TestInterface,可以获取到TestInterface的所有子类。
2)获取某个注解的所有类型/字段变量,支持注解参数匹配。
3)使用正则表达式获取所有匹配的资源文件
4)获取特定签名方法。
通常的用法有:
引入依赖jar
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
项目中使用:
// 初始化工具类
Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages(basePackages).addScanners(new SubTypesScanner()).addScanners(new FieldAnnotationsScanner()));
// 获取某个包下类型注解对应的类
Set<Class<?>> typeClass = reflections.getTypesAnnotatedWith(RpcInterface.class, true);
// 获取子类
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
// 获取注解对应的方法
Set<Method> resources =reflections.getMethodsAnnotatedWith(SomeAnnotation.class);
// 获取注解对应的字段
Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);
// 获取特定参数对应的方法
Set<Method> someMethods = reflections.getMethodsMatchParams(long.class, int.class);
Set<Method> voidMethods = reflections.getMethodsReturn(void.class);
Set<Method> pathParamMethods =reflections.getMethodsWithAnyParamAnnotated(PathParam.class);
// 获取资源文件
Set<String> properties = reflections.getResources(Pattern.compile(".*\\.properties"));
具体也可以参见官方文档
补充:Java中的反射:框架设计的灵魂
反射:框架设计的灵魂
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
好处:
1.可以在程序运行过程中,操作这些对象。
2.可以解耦,提高程序的可扩展性。
获取Class对象的方式:
1.Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2.类名.class:通过类名的属性class获取
多用于参数的传递
3.对象.getClass():getClass()方法在Object类中定义着。
多用于对象的获取字节码的方式
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
例如我们有一个Person类
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
我们写一个Demo用三种方式来获取Class对象
public class Demo1 {
public static void main(String [] args) throws Exception {
//1、Class.forName("类名")
Class cls1 = Class.forName("man.Person");
System.out.println(cls1);
//2、类名。class
Class cls2= Person.class;
System.out.println(cls2);
//3、对象.getClass()
Person p = new Person();
Class cls3=p.getClass();
System.out.println(cls3);
}
}
Class对象功能:
获取功能:
1.获取成员变量们
Field[] getFields() :获取所有public修饰的成员变量
Field getField(String name) 获取指定名称的 public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name)
2.获取构造方法们
Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)
Constructor getDeclaredConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()
3.获取成员方法们:
Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes)
4.获取全类名
String getName() * Field:成员变量
操作:
5.设置值
void set(Object obj, Object value)
6.获取值
get(Object obj)
7.忽略访问权限修饰符的安全检查
setAccessible(true):暴力反射
Constructor:构造方法
创建对象:
T newInstance(Object… initargs)
如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法* Method:方法对象
执行方法:
Object invoke(Object obj, Object… args)
获取方法名称:
String getName:获取方法名
同样对于上面的Person类我们对其新增带参数和不带参数的sleep方法并且写一个Demo来获取这些成员变量,构造方法以及成员方法
Person.java
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("eat...");
}
public void eat(String food){
System.out.println("eat..."+food);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
}
Demo2.java代码如下:
public class Demo2 {
public static void main(String [] args) throws Exception {
Class<Person> personClass = Person.class;
//获取成员变量
Field[] fields = personClass.getFields();
for(Field field:fields) {
System.out.println(field);
}
System.out.println("--------------");
Field a = personClass.getField("a");//获取a的值
Person p = new Person();
Object value=a.get(p);
System.out.println(value);
a.set(p, "zhangsan");//设置a的值
System.out.println(p);
System.out.println("=============");
//获取所有成员变量
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field d = personClass.getDeclaredField("d");
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);
//获取构造方法
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
Object person = constructor.newInstance("张三", 23);
System.out.println(person);
System.out.println("=======");
Constructor<Person> constructor1 = personClass.getConstructor();
System.out.println(constructor1);
Object person1 = constructor1.newInstance();
System.out.println(person1);
//获取成员方法
Method eat_method = personClass.getMethod("eat");
Person p1 = new Person();
eat_method.invoke(p1);
Method eat_method1 = personClass.getMethod("eat",String.class);
eat_method1.invoke(p1,"饭");
System.out.println("---------");
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
运行结果如下:
public java.lang.String man.Person.a
-------------- null Person{name=‘null', age=0, a=‘zhangsan', b=‘null', c=‘null', d=‘null'}
============= private java.lang.String man.Person.name private int man.Person.age public java.lang.String man.Person.a protected
java.lang.String man.Person.b java.lang.String man.Person.c private
java.lang.String man.Person.d null public
man.Person(java.lang.String,int) Person{name=‘张三', age=23, a=‘null',
b=‘null', c=‘null', d=‘null'}
======= public man.Person() Person{name=‘null', age=0, a=‘null', b=‘null', c=‘null', d=‘null'} eat… eat…饭
--------- public java.lang.String man.Person.toString() public java.lang.String man.Person.getName() public void
man.Person.setName(java.lang.String) public void
man.Person.eat(java.lang.String) public void man.Person.eat() public
void man.Person.setAge(int) public int man.Person.getAge() public
final void java.lang.Object.wait() throws
java.lang.InterruptedException public final void
java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws
java.lang.InterruptedException public boolean
java.lang.Object.equals(java.lang.Object) public native int
java.lang.Object.hashCode() public final native java.lang.Class
java.lang.Object.getClass() public final native void
java.lang.Object.notify() public final native void
java.lang.Object.notifyAll()
案例
需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:
1. 配置文件
2. 反射
步骤:
1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2. 在程序中加载读取配置文件
3. 使用反射技术来加载类文件进内存
4. 创建对象
5. 执行方法
为了实现创建任意类的对象,并且执行其中任意方法,我们再原有Person.java文件基础上新增Student.java,代码如下:
public class Student {
public void sleep(){
System.out.println("sleep...");
}
}
那么我们需要在src目录下添加pro.properties文件并写入以下配置信息
className=man.Student
methodName=sleep
接着我们来写这个案例ReflectTest.java,代码如下
public class ReflectTest {
public static void main(String [] args) throws Exception {
//加载配置文件
Properties pro = new Properties();
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//加载该类进内存
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
这样我们只需改变配置文件中的信息而不需要去改变任何代码就可以实现类以及类中的方法,整个目录结构如下
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://blog.csdn.net/chenwiehuang/article/details/83114641
猜你喜欢
- 本文实例讲述了Java Swing中JList选择事件 * ListSelectionListener用法。分享给大家供大家参考,具体如下:
- 排查@CacheEvict注解失效我简单看了一下《Spring实战》中的demo,然后就应用到业务代码中了,本以为如此简单的事情,竟然在代码
- Java连接SQLServer 2008数据库的步骤:1.到微软官方下载jdbc 并解压,得到sqljdbc.jar和sqljdbc4.ja
- 写在前面从Java 1.0开始,引入java.io包;到Java 1.4再扩展了java.nio包;再到java 1.7又添加了新的流类,使
- 一、叙述当Spring的事件(Application Event)为Bean和Bean之间的消息同步提供了支持。当一个Bean处理完成一个任
- 自定义TypeHandler映射JSON类型为List1. 实体类这里只展示需要映射的字段,分别在所需映射的字段和实体类上添加注解。&nbs
- 具体可见http://developer.android.com/tools/debugging/ddms.html。 DDMS为IDE和e
- 前言dynamic-tp是一个轻量级的动态线程池插件,它是一个基于配置中心的动态线程池,线程池的参数可以通过配置中心配置进行动态的修改,在配
- 前文本章是关于Java流程控制语句的最全汇总,本篇为汇总上篇。流程是人们生活中不可或缺的一部分,它表示人们每天都在按照一定的流程做事。比如出
- 题目:给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路
- 本文主要介绍在SpringMVC框架整合Junit框架进行单元测试。闲话少述,让我们直入主题。系统环境软件版本spring-webmvc4.
- 本文实例为大家分享了java实现简单的图书管理系统的具体代码,供大家参考,具体内容如下一、项目分布Book类: 定义了书的一些属性(书名,作
- 一个项目中需要使用两个数据库,Oracle 和Mysql,于是参考各个blog,实现此功能。写好后才发现,原来的事务失效了,我去...spr
- 前言关于mybatis-plus的简介以及基本使用,我在《SpringBoot整合mybatis-plus–入门超详细》一文中已做介绍,此处
- 1.什么是mybatis逆向工程在使用mybatis时需要程序员自己编写sql语句,针对单表的sql语句量是很大的,mybatis官方提供了
- 结果映射ResultMap引入resultMap–MyBatis中最强大的元素数据库字段名::实体类字段名:public
- 本文实例为大家分享了Swing拆分窗格控件JSplitPane的使用方法,供大家参考,具体内容如下package day1115;impor
- 问题:在web里面用iframe连接一个html文件 - html文件里面是超链接 -&nb
- 本文将介绍使用Spring Boot集成Mybatis并实现主从库分离的实现(同样适用于多数据源)。延续之前的Spring Boot 集成M
- 前言接口调试是每个软件开发从业者必不可少的一项技能,一个项目的的完成,可能接口测试调试的时间比真正开发写代码的时间还要多,几乎是每个开发的日