扫码关注官方订阅号
怎样提高反射的效率?
认证0级讲师
一. 善用API
比如,尽量不要getMethods()后再遍历筛选,而直接用getMethod(methodName)来根据方法名获取方法
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请自行实现
javapublic 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)); }
java
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方法差距不是很大。差距在于自己写轮寻和系统自带轮寻之间的效率。
除了缓存还有没其他方法?
要使用类信息,少查找class, field, method,缓存很重要,还有办法是生成代理类。要复制对象可以用CGLib的BeanCopier (其原理是运行时动态生成了用于复制某个类的代码(字节码))。 要提高Method.invoke性能,可用Java 7的MethodHandle (由于Method.invoke的JIT优化,差距不大)。 使用高版本JDK也很重要,反射性能一直在提高。
ReflectASM 通过字节码生成的方式加快反射速度
说了半天,都没有人提到"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以上不需要设置这两个配置
使用反射框架,如joor,或者apache的commons相关工具类
微信扫码关注PHP中文网服务号
QQ扫码加入技术交流群
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
PHP学习
技术支持
返回顶部
一. 善用API
比如,尽量不要
getMethods()
后再遍历筛选,而直接用getMethod(methodName)
来根据方法名获取方法二、缓存大法好~
比如,需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多:
为什么?当然是因为forName太耗时了。
p.s. cache请自行实现
顺便看一下getMethod方法,如果类的方法不是很多,getMethod和getMethods方法差距不是很大。差距在于自己写轮寻和系统自带轮寻之间的效率。
除了缓存还有没其他方法?
要使用类信息,少查找class, field, method,缓存很重要,还有办法是生成代理类。要复制对象可以用CGLib的BeanCopier (其原理是运行时动态生成了用于复制某个类的代码(字节码))。
要提高Method.invoke性能,可用Java 7的MethodHandle (由于Method.invoke的JIT优化,差距不大)。
使用高版本JDK也很重要,反射性能一直在提高。
ReflectASM 通过字节码生成的方式加快反射速度
说了半天,都没有人提到"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以上不需要设置这两个配置
使用反射框架,如joor,或者apache的commons相关工具类