https://segmentfault.com/q/1010000003004720
一
一. 善用API
比如,尽量不要getMethods()
后再遍历筛选,而直接用getMethod(methodName)
来根据方法名获取方法
二、缓存大法好~
比如,需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多:
// 1. 没有缓存
void createInstance(String className){
return Class.forName(className).newInstance();
}
// 2. 缓存forName的结果
void createInstance(String className){
cachedClass = cache.get(className);
if (cachedClass == null){
cachedClass = Class.forName(className);
cache.set(className, cachedClass);
}
return cachedClass.newInstance();
}
为什么?当然是因为forName太耗时了。
p.s. cache请自行实现
二
- 在系统启动阶段使用反射。
- 将反射得到元数据保存起来,使用时,只需从内存中调用即可。
- hotspot虚拟机会对执行次数较多的方法进行优化(例如使用jit技术)。
- 使用高性能的反射库,应该会比自己写缓存效果好。
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}
private Method getMethod0(String name, Class<?>[] parameterTypes) {
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
parameterTypes)) != null) {
return res;
}
if (!isInterface()) {
Class<? super T> c = getSuperclass();
if (c != null) {
if ((res = c.getMethod0(name, parameterTypes)) != null) {
return res;
}
}
}
Class<?>[] interfaces = getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Class<?> c = interfaces[i];
if ((res = c.getMethod0(name, parameterTypes)) != null) {
return res;
}
}
return null;
}
private static Method searchMethods(Method[] methods,
String name,
Class<?>[] parameterTypes)
{
Method res = null;
String internedName = name.intern();
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (m.getName() == internedName
&& arrayContentsEq(parameterTypes, m.getParameterTypes())
&& (res == null
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
res = m;
}
return (res == null ? res : getReflectionFactory().copyMethod(res));
}
顺便看一下getMethod方法,如果类的方法不是很多,getMethod和getMethods方法差距不是很大。差距在于自己写轮寻和系统自带轮寻之间的效率。
三
说了半天,都没有人提到"setAccessible(true)"...楼上的各位不是资深java程序员吧?
edit:
实话地告诉你,JDK1.6之后,对于method/field/constructor的invoke这类的反射,除了"setAccessible(true)"之外,再无须其它任何优化, 完爆以前cglib的fastmethod之流
当然了,将得到的method/field/constructor对象做缓存这是基本的
07-31 edit:
忘了补充一句:
如果你在jdk6上跑,且如果你反射的目标方法是getter/setter methods的话,记得加上配置:-XX:-UseFastEmptyMethods -XX:-UseFastAccessorMethods , 这两个配置的关闭是为了让accessor methods能够被jit; jdk7以上不需要设置这两个配置
四
要使用类信息,少查找class, field, method,缓存很重要,还有办法是生成代理类。要复制对象可以用CGLib的BeanCopier (其原理是运行时动态生成了用于复制某个类的代码(字节码))。
要提高Method.invoke性能,可用Java 7的MethodHandle (由于Method.invoke的JIT优化,差距不大)。
使用高版本JDK也很重要,反射性能一直在提高。
五
ReflectASM 通过字节码生成的方式加快反射速度
六
使用反射框架,如joor,或者apache的commons相关工具类