常德公司做网站,网站建设和网络搭建是一回事吗,石排东莞网站建设,工作室怎么网站备案前言在我们平时的工作或者面试中#xff0c;都会经常遇到“反射”这个知识点#xff0c;通过“反射”我们可以动态的获取到对象的信息以及灵活的调用对象方法等#xff0c;但是在使用的同时又伴随着另一种声音的出现#xff0c;那就是“反射”很慢#xff0c;要少用。难道…前言在我们平时的工作或者面试中都会经常遇到“反射”这个知识点通过“反射”我们可以动态的获取到对象的信息以及灵活的调用对象方法等但是在使用的同时又伴随着另一种声音的出现那就是“反射”很慢要少用。难道反射真的很慢那跟我们平时正常创建对象调用方法比慢多少? 估计很多人都没去测试过只是”道听途说“。下面我们就直接通过一些测试用例来直观的感受一下”反射“。正文准备测试对象下面先定义一个测试的类TestUser只有id跟name属性以及它们的getter/setter方法另外还有一个自定义的sayHi方法。public classTestUser {privateInteger id;privateString name;publicString sayHi(){return hi;}publicInteger getId() {returnid;}public voidsetId(Integer id) {this.id id;}publicString getName() {returnname;}public voidsetName(String name) {this.name name;}}测试创建100万个对象//通过普通方式创建TestUser对象Testpublic voidtestCommon(){long start System.currentTimeMillis();TestUser user null;int i 0;while(i1000000){i;user newTestUser();}long end System.currentTimeMillis();System.out.println(普通对象创建耗时(end - start ) ms);}//普通对象创建耗时10ms//通过反射方式创建TestUser对象Testpublic void testReflexNoCache() throwsException {long start System.currentTimeMillis();TestUser user null;int i 0;while(i1000000){i;user (TestUser) Class.forName(ReflexDemo.TestUser).newInstance();}long end System.currentTimeMillis();System.out.println(无缓存反射创建对象耗时(end - start ) ms);}//无缓存反射创建对象耗时926ms在上面这两个测试方法中笔者各自测了5次把他们消耗的时间取了一个平均值在输出结果中可以看到一个是10ms一个是926ms在创建100W个对象的情况下反射居然慢了90倍左右。wtf差距居然这么大难道反射真的这么慢下面笔者换一种反射的姿势继续测试一下看看结果如何//通过缓存反射方式创建TestUser对象Testpublic void testReflexWithCache() throwsException {long start System.currentTimeMillis();TestUser user null;Class rUserClass Class.forName(RefleDemo.TestUser);int i 0;while(i1000000){i;user(TestUser) rUserClass.newInstance();}long end System.currentTimeMillis();System.out.println(通过缓存反射创建对象耗时(end - start ) ms);}//通过缓存反射创建对象耗时41ms咦这种操作只需要41ms了大大提高了反射创建对象的效率。为什么会快这么多呢其实通过代码我们可以发现是Class.forName这个方法比较耗时它实际上调用了一个本地方法通过这个方法来要求JVM查找并加载指定的类。所以我们在项目中使用的时候可以把Class.forName返回的Class对象缓存起来下一次使用的时候直接从缓存里面获取这样就极大的提高了获取Class的效率。同理在我们获取Constructor、Method等对象的时候也可以缓存起来使用避免每次使用时再来耗费时间创建。测试反射调用方法Testpublic void testReflexMethod() throwsException {long start System.currentTimeMillis();Class testUserClass Class.forName(RefleDemo.TestUser);TestUser testUser(TestUser) testUserClass.newInstance();Method method testUserClass.getMethod(sayHi);int i 0;while(i100000000){i;method.invoke(testUser);}long end System.currentTimeMillis();System.out.println(反射调用方法耗时(end - start ) ms);}//反射调用方法耗时330msTestpublic void testReflexMethod() throwsException {long start System.currentTimeMillis();Class testUserClass Class.forName(RefleDemo.TestUser);TestUser testUser(TestUser) testUserClass.newInstance();Method method testUserClass.getMethod(sayHi);int i 0;while(i100000000){i;method.setAccessible(true);method.invoke(testUser);}long end System.currentTimeMillis();System.out.println(setAccessibletrue 反射调用方法耗时(end - start ) ms);}//setAccessibletrue 反射调用方法耗时188ms这里我们反射调用sayHi方法1亿次在调用了method.setAccessible(true)后发现快了将近一半。查看API可以了解到jdk在设置获取字段调用方法的时候会执行安全访问检查而此类操作会比较耗时所以通过setAccessible(true)的方式可以关闭安全检查从而提升反射效率。极致的反射除了上面的手段还有没有什么办法可以更极致的使用反射呢这里介绍一个高性能反射工具包ReflectASM。它是通过字节码生成的方式来实现的反射机制下面是一个跟java反射的性能比较。这里就不介绍它的用法了有兴趣的朋友可以直接传送过去https://github.com/EsotericSoftware/reflectasm结语最后总结一下为了更好的使用反射我们应该在项目启动的时候将反射所需要的相关配置及数据加载进内存中在运行阶段都从缓存中取这些元数据进行反射操作。大家也不用惧怕反射虚拟机在不断的优化只要我们方法用的对它并没有”传闻“中的那么慢当我们对性能有极致追求的时候可以考虑通过三方包直接对字节码进行操作。---------------------------------------------------------公众号博文同步Github仓库有兴趣的朋友可以帮忙给个Star哦码字不易感谢支持。https://github.com/PeppaLittlePig/blog-wechat推荐阅读看完本文有收获请转发分享给朋友吧关注「深夜里的程序猿」分享最干的干货