ReflectASM 是一个很小的 Java 库,它通过字节码生成的方式实现了读写字段、调用方法或构造实例等反射操作。由于 ReflectASM 是通过生成字节码的方式而非依赖于 Java 的反射,所以它的执行速度会更快,并且这种方式在操作基本类型的字段时可以避免装箱操作。
ReflectASM 的应用
下面通过几个简单的例子演示如何使用 ReflectASM。首先在使用 ReflectASM 的 API 之前,需要引入它的依赖:
com.esotericsoftware
reflectasm
1.11.9
maven
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.9</version>
</dependency>
读写字段
通过 FieldAccess 可以读写类的字段:
SomeClass someObject = // ...
FieldAccess access = FieldAccess.get(SomeClass.class);
access.set(someObject, "name", "Huey");
String name = (String) access.get(someObject, "name");
assertEquals(name, "Huey");
调用方法
通过 MethodAccess 可以调用对象实例的方法:
SomeClass someObject = // ...
MethodAccess access = MethodAccess.get(SomeClass.class);
access.invoke(someObject, "setName", "Huey");
String name = (String) access.invoke(someObject, "getName");
assertEquals(name, "Huey");
构造实例
通过 ConstructorAccess 可以构造对象实例:
ConstructorAccess access = ConstructorAccess.get(SomeClass.class);
SomeClass someObject = access.newInstance();
// do something with someObject.
索引
相比通过名称来访问成员,使用索引的方式会更快。如果需要重复地访问同一个成员,那么通过索引来访问该成员效率更高:
String[] names = // ...
SomeClass someObject = // ...
MethodAccess access = MethodAccess.get(SomeClass.class);
int addNameIndex = access.getIndex("addName");
for (String name : names) {
access.invoke(someObject, addNameIndex, name);
}
遍历字段
遍历一个类的所有字段:
FieldAccess access = FieldAccess.get(SomeClass.class);
for(int i = 0, n = access.getFieldCount(); i < n; i++) {
access.set(instanceObject, i, valueToPut);
}
复制类
应用中用到从一个类到另外一个类的copy使用ReflectASM性能会好很多,具体的方式如下: 其中对于耗时的get操作增加了缓存,代理类生成一次就够了
public class ReflectAsmManager {
private static final ConcurrentMap<Class, MethodAccess> localCache = Maps.newConcurrentMap();
public static MethodAccess get(Class clazz) {
if(localCache.containsKey(clazz)) {
return localCache.get(clazz);
}
MethodAccess methodAccess = MethodAccess.get(clazz);
localCache.putIfAbsent(clazz, methodAccess);
return methodAccess;
}
public static <F,T> void copyProperties(F from, T to) {
MethodAccess fromMethodAccess = get(from.getClass());
MethodAccess toMethodAccess = get(to.getClass());
Field[] fromDeclaredFields = from.getClass().getDeclaredFields();
for(Field field : fromDeclaredFields) {
String name = field.getName();
try {
Object value = fromMethodAccess.invoke(from, "get" + StringUtils.capitalize(name), null);
toMethodAccess.invoke(to, "set" + StringUtils.capitalize(name), value);
} catch (Exception e) {
// 设置异常,可能会没有对应字段,忽略
}
}
}
}
访问控制权限
需要注意的是,对于任何的 public 成员,ReflectASM 都可以访问;在同一个类加载器,ReflectASM 也可以访问protected 或不加修饰符的成员;ReflectASM 无法访问 private 成员。
参考:
Power by TeXt.