JOOR(反射库)使用
2020-06-09 本文已影响0人
jackcooper
github: https://github.com/jOOQ/jOOR
- 官方介绍
jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK’s reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better. http://www.jooq.org/products
- 大意为:
jOOR提供了一种更为直观的方式来构建JDK原生的反射调用,因为JDK提供的反射API使用起来较冗长(它对包java.lang.reflect进行了简单封装,使得反射更加方便)。
jOOR功能介绍
- 1、提供on()操作符对类名、Class、Object进行统一实例化为Reflect对象,后续所有的反射操作基于该Reflect对象。
- 2、有功能调用方式均被封装成返回Reflect对象的链式结构,在使用上使得代码更加简洁。
- 3、对方法的签名匹配封装了更完善的匹配规则,包括精确匹配exactMethod()、近似匹配similarMethod()【对函数参数的近似匹配(int -> Integer)】和基类搜索等。
- 4、调用私有方法的不需要显示调用setAccessible(),内部动态读取public标记自动适配。
- 5、更加简洁的实现了对象构造函数的反射调用create()方法。
- 6、函数的调用call()方法组合成了可以拼接在Reflect的对象后面的链式方法。
- 7、额外增加了高级操作符as(),它实现了类的代理访问以及POJO对象的get/set/is方法实现。
API方法介绍
/**
* https://github.com/jOOQ/jOOR
* Reflect实际是对原生java reflect进行封装,屏蔽了无关细节。
*
* Reflect.create 用来调用之前的类的构造方法,有两种重载,一种有参数,一种无参数
* Reflect.call 方法调用,传入方法名和参数,如有返回值还需要调用get
* Reflect.get 获取(field和method返回)值相关,会进行类型转换,常与call和field组合使用
* Reflect.field 获取属性值相关,需要调用get获取该值
* Reflect.set 设置属性相关。
*/
//1、通过类名转换成一个Reflect对象:
public static Reflect on(String name);
public static Reflect on(String name, ClassLoader classLoader);
public static Reflect on(Class<?> clazz);
//2、将一个类对象转换成一个Reflect对象:
public static Reflect on(Object object);
//3、修改一个AccessibleObject类型的对象的访问权限:
public static <T extends AccessibleObject> T accessible(T accessible);
//4、返回Reflect对象具体包装的类型,类型为Class或者对象,由操作符on()的重载参数决定:
public <T> T get();
//5、将name指定的field转换成一个Reflect对象,后续对field的操作变为对Reflect对象的操作:
public Reflect field(String name);
//6、返回当前Reflect对象的所有field属性,并转换成Reflect对象的map:
public Map<String, Reflect> fields();
//7、修改(获取)field属性值:
public Reflect set(String name, Object value);
public <T> T get(String name);
//8、反射调用name指定的函数,此函数封装了对函数的签名的精准匹配和近似匹配:
public Reflect call(String name);
public Reflect call(String name, Object... args);
//9、反射调用指定类的构造函数,也封装了精准匹配和近似匹配:
public Reflect create();
public Reflect create(Object... args);
//10、返回当前Reflect对象封装的对象类型:
public Class<?> type();
//11、给封装对象创建一个代理访问,还实现了对POJO对象的setXX/getXX/isxx功能(此为Reflect对象的高级功能):
public <P> P as(Class<P> proxyType);
实例一
// All examples assume the following static import:
import static org.joor.Reflect.*;
String world = on("java.lang.String") // on后面放入类的全名,这里是String类
.create("Hello World") // 将字符串“Hello World”,传入构造方法中
.call("substring", 6) // 执行subString这个方法,并且传入6作为参数
.call("toString") // 执行toString方法
.get(); // 得到包装好的类,这里是一个String对象
实例二
建立一个测试类
package kale.androidframework;
public class Kale {
private String name;
private String className;
Kale() {
}
Kale(String clsName) {
this.className = clsName;
}
public void setName(String name) {
this.name = name;
}
private String getName() {
return name;
}
public String getClassName() {
return className;
}
public static void method() {
}
}
这个类中有有参构造方法和无参构造方法,还有get和set方法。这里的类变量都是private的,有一个get方法也是private的。我们现在要尝试利用jOOR来访问变量和方法:
String name = null;
Kale kale;
// 【创建类】
kale = Reflect.on(Kale.class).create().get(); // 无参数
kale = Reflect.on(Kale.class).create("kale class name").get();// 有参数
System.err.println("------------------> class name = " + kale.getClassName());
// 【调用方法】
Reflect.on(kale).call("setName","调用setName");// 多参数
System.err.println("调用方法:name = " + Reflect.on(kale).call("getName"));// 无参数
// 【得到变量】
name = Reflect.on(kale).field("name").get();// 复杂
name = Reflect.on(kale).get("name");// 简单
System.err.println("得到变量值: name = " + name);
// 【设置变量的值】
Reflect.on(kale).set("className", "hello");
System.err.println("设置变量的值: name = " + kale.getClassName());
System.err.println("设置变量的值: name = " + Reflect.on(kale).set("className", "hello2").get("className"));
典型用法
- method 调用
//Instance methods on的参数是一个对象
//Static methods on的参数是一个类
// Instance methods
//value0 = "12";
final String value0 = Reflect.on((Object) "1234").call("substring", 0, 2).get();
// Static methods
//value1 = "true";
final String value1 = Reflect.on(String.class).call("valueOf", true).get();
- Field属性get/set操作
public static class TestField {
private static final int SF_INT1 = new Integer(0);
private static final Integer SF_INT2 = new Integer(0);
private final int F_INT1 = new Integer(0);
private final Integer F_INT2 = new Integer(0);
private TestField I_DATA;
}
//Instant fields,on的参数是一个对象
//Static fields,on的参数是一个类
// Instance fields
// ----------------
TestField testField = new TestField();
/**
* 修改final属性
*/
final Integer value0 = Reflect.on(testField).set("F_INT2", 1).get("F_INT2"); //value0 = 1;
/**
* 获取属性值
*/
final int value1 = Reflect.on(testField).field("F_INT2").get(); //value1 = 1;
/**
* 链式修改多个属性值
*/
Reflect.on(testField).set("F_INT1", 2).set("F_INT2", 2);
/**
* 复杂链式修改多个属性值
*/
Reflect.on(testField).set("I_DATA", Reflect.on(TestField.class).create())
.field("I_DATA").set("F_INT1", 3).set("F_INT2", 3);
// Static fields
// ----------------
/**
* 修改static final属性
*/
final int value2 = Reflect.on(TestField.class).set("SF_INT1", 4).get("SF_INT1"); //value2 = 4;
/**
* 获取静态属性值
*/
final int value3 = Reflect.on(TestField.class).field("SF_INT1").get(); //value3 = 4;
- 抽象代理
public interface StringProxy {
String substring(int beginIndex);
}
String substring = on("java.lang.String")
.create("Hello World")
.as(StringProxy.class) // 为包装类建立一个代理
.substring(6); // 访问代理方法
从上面的例子就可以看到jOOR明显的优势
:
- 1、简化了反射冗长的异常处理。
- 2、简化了对Class、Method、Field、Constructor反射类的实例化,改为统一Reflect替换。
- 3、支持private方法的调用,内部动态区分是否需要accessible()。
- 4、将反射调用封装为更流行的链式调用方式,代码更容易理解(类似Rxjava的封装方式)。
- 5、支持类型内部wrap转换(泛型实现)。
总结
在项目中需要较多地方使用反射时,可以采用jOOR的封装来简化反射的调用;后续需要进行反射优化时(比如对Class、Method、Field仅在首次调用时获取并缓存起来,后续仅仅调用缓存的invoke()),jOOR的统一封装对优化也提供了便利。