java 反射的效率_如何提高使用Java反射的效率?

前言

在我们平时的工作或者面试中,都会经常遇到“反射”这个知识点,通过“反射”我们可以动态的获取到对象的信息以及灵活的调用对象方法等,但是在使用的同时又伴随着另一种声音的出现,那就是“反射”很慢,要少用。难道反射真的很慢?那跟我们平时正常创建对象调用方法比慢多少? 估计很多人都没去测试过,只是”道听途说“。下面我们就直接通过一些测试用例来直观的感受一下”反射“。

正文

准备测试对象

下面先定义一个测试的类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(i<1000000){++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(i<1000000){++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(i<1000000){++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(i<100000000){++i;

method.invoke(testUser);

}long end =System.currentTimeMillis();

System.out.println("反射调用方法耗时:"+(end - start ) + "ms");

}//反射调用方法耗时:330ms

@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(i<100000000){++i;

method.setAccessible(true);

method.invoke(testUser);

}long end =System.currentTimeMillis();

System.out.println("setAccessible=true 反射调用方法耗时:"+(end - start ) + "ms");

}//setAccessible=true 反射调用方法耗时:188ms

这里我们反射调用sayHi方法1亿次,在调用了method.setAccessible(true)后,发现快了将近一半。查看API可以了解到,jdk在设置获取字段,调用方法的时候会执行安全访问检查,而此类操作会比较耗时,所以通过setAccessible(true)的方式可以关闭安全检查,从而提升反射效率。

极致的反射

除了上面的手段,还有没有什么办法可以更极致的使用反射呢?这里介绍一个高性能反射工具包ReflectASM。它是通过字节码生成的方式来实现的反射机制,下面是一个跟java反射的性能比较。

format,png

format,png

format,png

这里就不介绍它的用法了,有兴趣的朋友可以直接传送过去:https://github.com/EsotericSoftware/reflectasm

结语

最后总结一下,为了更好的使用反射,我们应该在项目启动的时候将反射所需要的相关配置及数据加载进内存中,在运行阶段都从缓存中取这些元数据进行反射操作。大家也不用惧怕反射,虚拟机在不断的优化,只要我们方法用的对,它并没有”传闻“中的那么慢,当我们对性能有极致追求的时候,可以考虑通过三方包,直接对字节码进行操作。

---------------------------------------------------------

公众号博文同步Github仓库,有兴趣的朋友可以帮忙给个Star哦,码字不易,感谢支持。

https://github.com/PeppaLittlePig/blog-wechat

推荐阅读

看完本文有收获?请转发分享给朋友吧

关注「深夜里的程序猿」,分享最干的干货

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571935.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

个人项目-数独

项目源代码的Github链接 https://github.com/yaoling1997/softwareFirstHomework 需求分析 一、生成数独 命令&#xff1a;sudoku.exe -c n 要求&#xff1a; (1)输出到sudoku.txt (2)不重复 (3)1<n<1000000 (4)可以处理异常情况&#xff0c;如&#xff1a;sudoku.exe -c…

navicat premium 连接出现的问题

1、listener does not currently know of service requested in connect descriptor 2、问题截图&#xff1a; 3、问题原因&#xff1a;服务名或者SID不正确 4、改正方法&#xff1a;打开 图中tnsnames.ora文件 找到 XE就是服务名 正确连接&#xff1a; 转载于:https://www.cnb…

quartz java spring_从零开始学 Java - Spring 使用 Quartz 任务调度定时器

生活的味道睁开眼看一看窗外的阳光&#xff0c;伸一个懒腰&#xff0c;拿起放在床一旁的水白开水&#xff0c;甜甜的味道&#xff0c;晃着尾巴东张西望的猫猫&#xff0c;在窗台上舞蹈。你向生活微笑&#xff0c;生活也向你微笑。请你不要询问我的未来&#xff0c;这有些可笑。…

excel查重复_智学网怎么登录 智学网怎么查分数 智学网统一登录平台网址

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到最新文章了。每天都有分享。完全是免费订阅&#xff0c;请放心关注。注&#xff1a;本文转载自网络&#xff0c;不代表本平台立场&#xff0c;仅供读者参考&…

树莓派Java程序运行_树莓派上Java程序作为linux服务并开机自动启动

http://www.iigrowing.cn/shu_mei_pai_shang_java_cheng_xu_zuo_wei_linux_fu_wu_bing_kai_ji_zi_dong_qi_dong.html刚刚买了&#xff0c; 树莓派&#xff0c; 准备做一些程序&#xff0c; 放到树莓派上&#xff0c; 平时树莓派上不接显示器等各种设备&#xff0c;直接随着adsl…

小程序 mathjs渲染公式_Mac 3D渲染和动画制作----KeyShot 9 Pro

KeyShot 9 Pro for Mac是应用在Mac上的一款3D渲染和动画制作软件&#xff0c;keyshot是您快速创建精彩视觉效果所需的一切。在实时3D渲染工作流程显示结果即时&#xff0c;缩短了创建逼真的产品拍摄的时间。从科学上准确的材料和环境预设到高级材料编辑和动画&#xff0c;创建交…

用AsyncTask来获取网络图片

先看下运行结束 这里有两个Button 点击第一个Button运行的结果&#xff01;第一张有一个旋转的灰色圈圈&#xff01; 点击第二个Button运行的结果如下&#xff1a;带进度条的 ok,看下实现方法 先在配置清单中加一个访问网络的权限&#xff01; <uses-permission android:nam…

bilibili有电脑版吗_哪个手机便签软件有电脑版?有跨平台的桌面便签软件吗 - 学显...

如果仔细观察的话&#xff0c;你会发现&#xff1a;现在很多手机桌面上都有一款名叫“便签”的app小软件。其实&#xff0c;这是手机系统自带的一款备忘小工具&#xff0c;是为了方便用户记事而设计的。也就是说&#xff0c;平时如果有什么事儿需要记下来的话&#xff0c;就可以…

win10关机后自动重启_安卓手机重启和关机后再开机,区别原来这么大!别不当回事...

现在大家用智能手机&#xff0c;只会在以下几种情况关机&#xff0c;一种是用到没电&#xff0c;自动关机了。另一种是手机有点卡顿&#xff0c;通过关机再开机的方式&#xff0c;释放RAM内存&#xff0c;提高手机运行速度。而现在的很多手机&#xff0c;比如小米手机&#xff…

前端周报:前端面试题及答案总结;JavaScript参数传递的深入理解

1、2017前端面试题及答案总结 |掘金技术征文 "金三银四&#xff0c;金九银十"&#xff0c;用来形容求职最好的几个月。但是随着行业的饱和&#xff0c;初中级前端er就业形势不容乐观。 行业状态不可控&#xff0c;我们能做的当然只是让自己变得更加具有竞争力。 今年…

python二级考试真题_全国BIM技能等级考试真题全套(一/二级,全专业,28套)

BIM技能等级考试即将到来&#xff0c;你准备好了吗&#xff1f;今日为大家整理了一套网友上传的BIM等级考试全套真题&#xff0c;供大家学习参考~BIM一级真题解析课程限免&#xff1a;(点我)全国BIM技能等级考试真题解析(一级)仅限6月5日一天免费第一期全国BIM技能等级考试一级…

Awk使用方法简介

AWK AWK简介&#xff1a;awk是一个强大的文本分析工具&#xff0c;相对于grep的查找&#xff0c;sed的编辑&#xff0c;awk在其对数据分析并生成报告时&#xff0c;显得尤为强大。简单来说awk就是把文件逐行的读入&#xff0c; 以空格为默认分隔符将每行切片…

矩形波如何傅立叶展开_金科文化会不会连续拉板?两位同学展开激辩

【编者按&#xff1a;金科文化是我们昨晚理论上留下的两道作业题之一&#xff0c;要求同学们根据课程内容&#xff0c;判断一下它是否符合连板青云的条件&#xff1f;后市如何预判&#xff1f;操作计划怎么制定&#xff1f;今天&#xff0c;很多同学就此展开了分析和讨论。今晚…

java web 不用框架_MyShop-不用框架的基础javaweb项目

javaweb基础开发Servletjspmysqlhtmlcssjs(找一个前端模板&#xff0c;一大堆html,自己写的没有模板的美观)数据库设计来一个最基础的用户表drop table ifexists myshop_user;create table myshop_user(USER_ID varchar(32) not null,USER_NAME varchar(20) not null,USER_PASS…

程序包管理器控制台 Add-Migration 用法

需要注意的是&#xff1a; 1.任何对数据库的操作都在代码和程序包管理控制台完成&#xff0c;千万不要自己去修改数据库&#xff0c;no&#xff01; 2.ef中创建数据库的表必须要有主键~&#xff01;否则 就不让你成功~ 现在来说如何映射 第一步创建在代码model中创建类 第二步 …

ipad如何连接电脑_电脑无法连接外网远程调试,一文教你如何用手机让台式机连接外网...

在弱电施工中&#xff0c;设备调试是一个很重要的环节&#xff0c;施工这么久就是为了实现弱电各系统的功能&#xff0c;调试是每一个弱电人系必需会的技能&#xff0c;也是检验你结合能力一种体现。在调试中会遇到各种你想不到的问题&#xff0c;当遇到问题时&#xff0c;你应…

java 多线程两种方式_JAVA多线程实现的两种方式

java多线程实现方式主要有两种&#xff1a;继承Thread类、实现Runnable接口1、继承Thread类实现多线程继承Thread类的方法尽管被我列为一种多线程实现方式&#xff0c;但Thread本质上也是实现了Runnable接口的一个实例&#xff0c;它代表一个线程的实例&#xff0c;并且&#x…

安卓手机浏览器排行_安卓手机性能排行榜:国产手机集体“出位”,华为却在角落哭泣?...

华为手机的芯片一直都坚称是国产的骄傲&#xff0c;但是现在的华为芯片出现了一系列的问题&#xff0c;甚至有人预言在今年九月份之后&#xff0c;华为就不再会获得台积电的芯片供应了。这样&#xff0c;对华为来说无疑是不好的势头&#xff0c;而且芯片刚被市场认可&#xff0…

_Linux结束进程到底有多少种方法?

请关注本头条号&#xff0c;每天坚持更新原创干货技术文章。如需学习视频&#xff0c;请在微信搜索公众号“智传网优”直接开始自助视频学习。1. 前言我们经常在Linux里使用kill命令来结束某后台进程。但kill命令实际上是向进程发送信号&#xff0c;并且有多种信号。终止运行一…

mulitpartfile怎么接收不到值_光端机电源正常,但是运行不了怎么办?

光端机&#xff0c;是光信号传输的终端设备&#xff0c;在安防领域有很好的应用。伴随着监控的发展&#xff0c;视频光端机就是把1路到多路的模拟视频信号通过各种编码转换成光信号通过光纤介质来传输的设备分&#xff0c;分为模拟光端机和数字光端机。其中&#xff0c;光传输系…