Java-反射性能优化和工具包ReflectASM
Java反射动态的获取到对象的信息以及灵活的调用对象方法等,但是听说效率很慢,测试下。
普通创建对象对比反射创建对象
public class TestUser {private Integer id;private String name;public String sayHi(){ return "hi";}public Integer getId() { return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}public class TestDemo {public static void main(String[] argv){testCommon();testReflexNoCache();}public void testCommon(){long start = System.currentTimeMillis();TestUser user = null;int i = 0;while(i<1000000){++i;user = new TestUser();}long end = System.currentTimeMillis();System.out.println("普通对象创建耗时:"+(end - start ) + "ms");}// 通过反射方式创建TestUser对象public void testReflexNoCache() throws Exception {long start = System.currentTimeMillis();TestUser user = null;int i = 0;while(i<1000000){++i;user = (TestUser) Class.forName("ReflexDemo.TestUser").newInstance();}long end = System.currentTimeMillis();System.out.println("无缓存反射创建对象耗时:"+(end - start ) + "ms");}
}输出:
普通对象创建耗时:10ms
无缓存反射创建对象耗时:966ms
创建100W个对象的情况下,反射居然慢了90倍左右!
通过缓存反射方式创建对象
public void testReflexWithCache() throws Exception {long start = System.currentTimeMillis();TestUser user = null;Class rUserClass = Class.forName("RefleDemo.TestUser");int i = 0;while(i<1000000){++i;user = (TestUser) rUserClass.newInstance();}long end = System.currentTimeMillis();System.out.println("通过缓存反射创建对象耗时:"+(end - start ) + "ms");}输出:
通过缓存反射创建对象耗时:41ms
通过代码我们可以发现,是Class.forName这个方法比较耗时,它实际上调用了一个本地方法,通过这个方法来要求JVM查找并加载指定的类。
所以我们在项目中使用的时候,可以把Class.forName返回的Class对象缓存起来,下一次使用的时候直接从缓存里面获取,这样就极大的提高了获取Class的效率。同理,在我们获取Constructor、Method等对象的时候也可以缓存起来使用,避免每次使用时再来耗费时间创建。
为什么Java反射性能慢效率低
程序运行期的即时编译器(JIT 编译器,Just In Time Compiler)把字节码文件编译成机器码的过程;其中即时编译器(JIT)在运行期的优化过程对于程序运行来说更重要,Java虚拟机在编译阶段的代码优化就在这里进行,由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射操作的性能要比非反射操作慢,因此应该避免在对性能敏感的应用程序中频繁使用Java反射来创建对象。
反射调用方法
public void testReflexMethod() throws Exception {long start = System.currentTimeMillis();Class testUserClass = Class.forName("RefleDemo.TestUser");TestUser testUser = (TestUser) testUserClass.newInstance();Method method = testUserClass.getMethod("sayHi");int i = 0;while(i<100000000){++i;method.invoke(testUser);}long end = System.currentTimeMillis();System.out.println("反射调用方法耗时:"+(end - start ) + "ms");}输出:
反射调用方法耗时:330ms
通过setAccessible(true)的方式可以关闭安全检查
public void testReflexMethod() throws Exception {long start = System.currentTimeMillis();Class testUserClass = Class.forName("RefleDemo.TestUser");TestUser testUser = (TestUser) testUserClass.newInstance();Method method = testUserClass.getMethod("sayHi");int i = 0;while(i<100000000){++i;method.setAccessible(true);method.invoke(testUser);}long end = System.currentTimeMillis();System.out.println("setAccessible=true 反射调用方法耗时:"+(end - start ) + "ms");}输出:
setAccessible=true 反射调用方法耗时:188ms
查看API可以了解到,jdk在设置获取字段,调用方法的时候会执行安全访问检查,而此类操作会比较耗时,所以通过setAccessible(true)的方式可以关闭安全检查,从而提升反射效率。
高性能反射工具包ReflectASM
ReflectASM通过字节码生成的方式实现了更为高效的反射机制。执行时会生成一个存取类来 set/get 字段,访问方法或创建实例。
依赖:
<!--java 反射工具包 -->
<!-- https://mvnrepository.com/artifact/com.esotericsoftware/reflectasm -->
<dependency><groupId>com.esotericsoftware</groupId><artifactId>reflectasm</artifactId><version>1.11.3</version>
</dependency>
asm框架包依赖:
<dependency><groupId>org.ow2.asm</groupId><artifactId>asm</artifactId><version>9.2</version>
</dependency>
ConstructorAccess反射来调用构造方法
- public static ConstructorAccess get(Class type):生成字节码的方式创建 ConstructorAccess
- public abstract T newInstance():创建实例。
创建测试类User:
class User {public int age;public String name;public User() {}public User(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "User{" + "age=" + age + ", name='" + name + '\'' + '}';}public void update(int age, String name) {this.age = age;this.name = name;}
}
ReflectAsm反射来调用构造方法
public class ReflectAsmDemo {public static void main(String[] args) throws Exception {testConstructorAccess();}/*** ReflectAsm反射来调用构造方法*/public static void testConstructorAccess() {ConstructorAccess<User> constructorAccess = ConstructorAccess.get(User.class);User user = constructorAccess.newInstance();System.out.println(user);}
}输出:
User{age=0, name='null'}
FieldAccess反射获取属性
- public static FieldAccess get(Class type):生成字节码的方式创建 FieldAccess
- public void set(Object instance, String fieldName, Object value):设置fieldName属性值。
- public Object get(Object instance, String fieldName):获取fieldName属性值。
- public int getFieldCount():获取字段总个数。
- public String[] getFieldNames():获取字段名称数组。
- public int getIndex(String fieldName):获取指定字段index。
public class ReflectAsmDemo {public static void main(String[] args) throws Exception {testFieldAccess();}/*** ReflectAsm反射来set/get字段值*/public static void testFieldAccess() {FieldAccess fieldAccess = FieldAccess.get(User.class);String[] fieldNames = fieldAccess.getFieldNames();for (String fieldName : fieldNames) {System.out.println("fieldName=" + fieldName);}System.out.println("FieldCount=" + fieldAccess.getFieldCount());System.out.println("index=" + fieldAccess.getIndex("name"));User target = new User(28,"lili");fieldAccess.set(target, "age", 1);int age = (Integer)fieldAccess.get(target, "age");System.out.println(age);}
}输出:
fieldName=age
fieldName=name
FieldCount=2
index=1
1
FieldAccess访问私有字段,会报错Unable to find non-private field: …。
如果想访问私有字段,可以使用反射功能先放开权限。
Field field = Animal.class.getDeclaredField(“id”);
field.setAccessible(true);
MethodAccess反射调用方法
- public static MethodAccess get(Class type):生成字节码的方式创建 MethodAccess
- public String[] getMethodNames():获取方法名称数组。
- public Object invoke(Object object, String methodName, Object… args):用方法名定位反射方法
- public int getIndex(String methodName, Class… paramTypes):用方法和字段的索引定位反射方法,性能高。
- public abstract Object invoke(Object var1, int index, Object… var3):index是上面函数获取的索引index。
public class ReflectAsmDemo {public static void main(String[] args) throws Exception {testMethodAccess();testMethodIndexAccess();}/*** ReflectAsm反射调用方法* 用名称定位反射方法*/public static void testMethodAccess() {User target = new User();MethodAccess methodAccess = MethodAccess.get(User.class);String[] methodNames = methodAccess.getMethodNames();for (String methodName : methodNames) {System.out.println("methodName=" + methodName);}methodAccess.invoke(target, "update", 1, "jack");System.out.println(target);}/*** ReflectAsm反射调用方法* 用方法和字段的索引定位反射方法,性能高*/public static void testMethodIndexAccess() {User target = new User();MethodAccess methodAccess = MethodAccess.get(User.class);int index = methodAccess.getIndex("update", int.class, String.class);methodAccess.invoke(target, index, 1, "jack");System.out.println(target);}
}输出:
methodName=toString
methodName=update
User{age=1, name='jack'}
User{age=1, name='jack'}
ReflectASM执行效率比对
public class ReflectASMDemo {public static void main(String[] args) throws Exception {ReflectASMDemo test = new ReflectASMDemo();test.testJdkReflect();test.testReflectAsmName();test.testReflectAsmIndex();}/*** JDK反射调用方法* @throws Exception*/public void testJdkReflect() throws Exception {User target = new User();long start = System.currentTimeMillis();Method method = target.getClass().getMethod("update", int.class, String.class);for (int i = 0; i < 100000000; i++) {method.invoke(target, 1, "jack");}long end = System.currentTimeMillis();System.out.println("timeout=" + (end - start));//418 450 426 430}/*** ReflectAsm反射调用方法* 用名称定位反射方法*/public void testReflectAsmName() {User target = new User();MethodAccess access = MethodAccess.get(User.class);//生成字节码的方式创建UserMethodAccesslong start = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {access.invoke(target, "update", 1, "jack");}long end = System.currentTimeMillis();System.out.println("timeout=" + (end - start));//88 64 66 50}/*** ReflectAsm反射调用方法* 用方法和字段的索引定位反射方法,性能高*/public void testReflectAsmIndex() {User target = new User();MethodAccess access = MethodAccess.get(User.class);int index = access.getIndex("update", int.class, String.class);long start = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {access.invoke(target, index, 1, "jack");}long end = System.currentTimeMillis();System.out.println("timeout=" + (end - start));//14 12 11 13}/*** ReflectAsm反射来set/get字段值*/public void testFieldAccess() {User target = new User();FieldAccess fieldAccess = FieldAccess.get(target.getClass());fieldAccess.set(target, "age", 1);int age = (Integer)fieldAccess.get(target, "age");System.out.println(age);}/*** ReflectAsm反射来调用构造方法*/public void testConstructorAccess() {ConstructorAccess<User> constructorAccess = ConstructorAccess.get(User.class);User userService = constructorAccess.newInstance();System.out.println(userService);}/*** 查找方法的索引*/public void testIndex() {User target = new User();MethodAccess methodAccess = MethodAccess.get(target.getClass());int index = methodAccess.getIndex("update", int.class, String.class);System.out.println(index);}
}class User {public int age;public String name;public void update(int age, String name) {}
}
结果发现,reflectASM效率明显高于Java反射获取,并且reflectASM提供通过方法名定位索引,然后通过索引调用方法,进一步提升方法调用效率。
通过reflectASM实现对象拷贝
public class BeanUtil {/*** 大小写可以忽略* 下划线 _ 被忽略* NULL值和空字符串不会覆盖新值** @param source* @param target* @param <T>* @return*/public static <T> T copyPropertiesIgnoreCase(Object source, Object target) {Map<String, Field> sourceMap = CacheFieldMap.getFieldMap(source.getClass());CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> {Field field = sourceMap.get(it.getName().toLowerCase().replace("_", ""));if (field != null) {it.setAccessible(true);field.setAccessible(true);try {//忽略null和空字符串if(field.get(source)!=null)it.set(target, field.get(source));} catch (IllegalAccessException e) {e.printStackTrace();}}});System.out.println(target.toString());return (T) target;}private static class CacheFieldMap {private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();private static Map<String, Field> getFieldMap(Class clazz) {Map<String, Field> result = cacheMap.get(clazz.getName());if (result == null) {synchronized (CacheFieldMap.class) {if (result == null) {Map<String, Field> fieldMap = new HashMap<>();for (Field field : clazz.getDeclaredFields()) {fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);}cacheMap.put(clazz.getName(), fieldMap);result = cacheMap.get(clazz.getName());}}}return result;}}
}
MapToObjectIgnoreCaseUtil:
package 对象拷贝;import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class MapToObjectIgnoreCaseUtil {public static void main(String[] args) throws Exception {Map<Object, Object> map = new HashMap<>();map.put("fc_id", "TK");map.put("fc_merch_id", "123456");map.put("fc_merch_name", "中金");MerchInfo merchInfo = new MerchInfo();System.out.println(merchInfo);merchInfo = (MerchInfo) MapToObjectIgnoreCaseUtil.mapToObject(map, merchInfo.getClass());System.out.println(merchInfo);}public static Object mapToObject(Map<Object, Object> map, Class<?> beanClass) throws Exception {if (map == null)return null;Map<Object, Object> map2 = new HashMap<>();Set<Object> keySet = map.keySet();for(Object key : keySet){map2.put(key.toString().toLowerCase().replace("_", ""), map.get(key));}Object obj = beanClass.newInstance();Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {int mod = field.getModifiers();if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {continue;}field.setAccessible(true);if (map2.containsKey(field.getName().toLowerCase().replace("_", ""))) {field.set(obj, map2.get(field.getName().toLowerCase().replace("_", "")));}}return obj;}
}class MerchInfo{public String fcID;public String fcMerchId;public String fcMerchName;public String getFcID() {return fcID;}public void setFcID(String fcID) {this.fcID = fcID;}public String getFcMerchId() {return fcMerchId;}public void setFcMerchId(String fcMerchId) {this.fcMerchId = fcMerchId;}public String getFcMerchName() {return fcMerchName;}public void setFcMerchName(String fcMerchName) {this.fcMerchName = fcMerchName;}@Overridepublic String toString() {return "MerchInfo{" +"fcID='" + fcID + '\'' +", fcMerchId='" + fcMerchId + '\'' +", fcMerchName='" + fcMerchName + '\'' +'}';}
}
Java-反射性能优化和工具包ReflectASM相关推荐
- Java中性能优化的35种方法汇总
原文地址:http://www.jb51.net/article/102831.htm 前言 对程序员们来说,代码优化是一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于 ...
- 44个Java代码性能优化总结
转载自 44个Java代码性能优化总结 代码优化的最重要的作用应该是:避免未知的错误.在代码上线运行的过程中,往往会出现很多我们意想不到的错误,因为线上环境和开发环境是非常不同的,错误定位到最后往往是 ...
- 【Java】44个Java代码性能优化总结
1.概述 转载:44个Java代码性能优化总结 代码优化的最重要的作用应该是:避免未知的错误.在代码上线运行的过程中,往往会出现很多我们意想不到的错误,因为线上环境和开发环境是非常不同的,错误定位到最 ...
- Java程序性能优化——设计优化
原文出自:http://blog.csdn.net/anxpp/article/details/51914119,转载请注明出处,谢谢! 1.前言 OK,之前写了一篇文章:"23种设计模式介 ...
- java 代码性能优化_Java代码性能优化的几个小技巧
Java代码性能优化的几个小技巧 时间:2017-08-07 来源:华清远见JAVA学院 代码优化是程序员必须懂得一门学问,所以不管是程序员还是准程序员,养成良好的代码优化习惯都是必须要养成的 ...
- java代码统计收藏量_干货收藏 | 35个Java 代码性能优化总结(上)
原标题:干货收藏 | 35个Java 代码性能优化总结(上) 前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这 ...
- [译]GC专家系列5-Java应用性能优化的原则
原文链接:http://www.cubrid.org/blog/dev-platform/the-principles-of-java-application-performance-tuning/ ...
- java常见性能优化_十大最常见的Java性能问题
java常见性能优化 Java性能是所有Java应用程序开发人员都关心的问题,因为快速使应用程序与使其正常运行同等重要. 史蒂文·海恩斯(Steven Haines)使用他在Java性能问题上的个人经 ...
- Java 程序性能优化《第一章》Java性能调优概述 1.4小结
Java 程序性能优化<第一章>1.4小结 通过本章的学习,读者应该了解性能的基本概念及其常用的参考指标.此外,本章还较为详细的介绍了与性能调优相关的两个重要理论--木桶原理以及Amdah ...
最新文章
- javascript iterator
- 9path 导致的一场冤假错案
- UA OPTI512R 傅立叶光学导论15 2-D Fourier变换与Hankel变换
- 数据中心电池室管理之经济实用性方法的探索
- 以 Kubernetes 为代表的容器技术,已成为云计算的新界面
- xxx in ‘Anonymous class derived from xxx clashes with ‘call(T)‘ in xxx attempting to use incompati
- python 操作redis,存取为字节格式,避免转码加
- Win7 U盘安装Ubuntu16.04 双系统
- LXReorderableCollectionViewFlowLayout
- 将ubuntu的home迁移至第二块磁盘
- mysql数据库连接数瓶颈_MySQL数据库性能优化之硬件瓶颈分析
- 笔记本电脑配置知识大全
- 64qam带宽计算_64QAM有效传输速率计算
- 信号与系统matlab实验报告,信号与系统实验报告.doc
- Spring之IOC概念、Bean对象创建及DI注入的三种方式
- Delphi7 将Excel导入数据库
- Git上传代码报错Push rejected: Push to origin/master was rejected
- 开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型...
- android 一直开机画面,解决:Android模拟器一直停留在开机画面
- 微信小程序自动保留空格换行
热门文章
- 在html中写js打开是乱码,javascript脚本中文乱码如何解决?
- 计算机架构设计的8个伟大思想
- 51单片机矩阵键盘C程序
- 自学软件测试的面试经验(一)~
- 3D模型 在Android Studio 中的应用
- win10远程计算机或设备将不接受连接
- php 框架注解,laravel框架常用的注解
- 二元logistic模型案例_SPSS二项logistic回归分析案例实践,做个预测模型
- [css] 页面重构“鑫三无准则” 之“无宽度”准则
- 计算机技术类岗位英文简历,计算机科学与技术类专业英文简历模板.docx