Java反射性能究竟如何?

本贴最后更新于 3141 天前,其中的信息可能已经斗转星移

以前的开发,都没有在项目中频繁使用反射的场景,我对反射的使用都局限于系统启动时,根据配置文件的内容反射来初始化某个对象。


新公司的一个项目很有意思,采用了领域驱动设计的思想设计,业务层操作的对象成为bo(business object),透明化了持久化层及持久层的实体(entity),若需要与持久层交互,则通过一个Convertor对象进行bo与entity间的转换。

例如,将一批User数据存入数据库:

		UserBo[] users = ...//一个长度为n的数组
		UserEntity[] entitys = new UserEntity[n];
		for(int i = 0;i<n;i++){
			TourGuideEntity entity = userConvertor.reverse(users[i]);
			entitys[i] = entity;
		}
		//通过hibernate持久化entitys

 

而Convertor类在编写时,由于entity中的属性较多,程序员们懒得去写一堆类似entity.SetName(bo.getName())的代码,于是通过反射直接去赋值,主要代码如下:

	//获取字段
	public static Field getField(Class<?> clazz, String fieldName) 
		for(Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				Field res = superClass.getDeclaredField(fieldName);
				return res;
			} catch(NoSuchFieldException e) {
				// Field不在当前类定义,继续向上转型
			}
		}
		return null;
	}
//设置字段值
public static void setField(Bo bo,Entity entity,Field f){
	Object value = f.get(bo);
	f.set(entity, value);
}</pre>


这套流程设计优雅,但性能是在是惨不忍睹。转换1.8万条数据居然花了120秒。。

用jvisualvm排查了一下,发现大量的时间消耗在了getField方法上。

简单看一下JDK的源码:

    public Field getDeclaredField(String name)
        throws NoSuchFieldException, SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        Field field = searchFields(privateGetDeclaredFields(false), name);
        if (field == null) {
            throw new NoSuchFieldException(name);
        }
        return field;
    }
private static Field searchFields(Field[] fields, String name) {
    String internedName = name.intern();
    for (int i = 0; i &lt; fields.length; i++) {
        if (fields[i].getName() == internedName) {
            return getReflectionFactory().copyField(fields[i]);
        }
    }
    return null;
}</pre>




getField/getDeclaredField方法需要先通过privateGetDeclaredFields获取所有字段,然后遍历所有字段查找名称为name的,显然是十分低效的。

结论是,在反射中,getField方法非常耗时,set/get方法是很快的。

所以,我们应该尽量在初始化时就完成getField的工作,set/get时直接使用初始化时得到的field。

例如上面存储entity的例子,我们可以在Convertor中加一个init方法,在初始化时便通过反射去解析好bo、entity间的field,并建立其对应关系,在转换时直接使用这些对应关系即可。优化后,只需90毫秒就可完成1.8万数据的转换,速度提高了上千倍。


  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3169 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • huangxuan

    用反射起码的加上缓存 . 最好是用 cglib

  • 其他回帖
  • someone

    不会,初始化只调用一次 getDeclaredField

  • someone

    cglib 是个好点子,或者干脆直接用 JDK 的动态代理?
    不过这玩意一般都是用于 service 层,在这个例子中得用到大量的 pojo 中,如何让代码简介优雅又兼顾性能还得好好设计一下[em01]。

  • sharmine2

    有没有想过使用 cglib? 或者使用 beanutils 的 copyproperties。当然这个解决方案也是很好的

  • 查看全部回帖

推荐标签 标签

  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    478 引用 • 902 回帖
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    76 引用 • 149 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    198 引用 • 120 回帖 • 1 关注
  • 音乐

    你听到信仰的声音了么?

    59 引用 • 509 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 232 回帖 • 9 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    103 引用 • 126 回帖 • 446 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    205 引用 • 357 回帖
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 423 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6603 引用 • 29629 回帖 • 251 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 247 回帖 • 171 关注
  • gRpc
    10 引用 • 8 回帖 • 55 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • 笔记

    好记性不如烂笔头。

    305 引用 • 780 回帖
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    14 引用 • 7 回帖 • 2 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    53 引用 • 85 回帖 • 2 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    207 引用 • 2031 回帖
  • 倾城之链
    23 引用 • 66 回帖 • 104 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    82 引用 • 122 回帖 • 621 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 8 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 509 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    18876 引用 • 70678 回帖 • 2 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 21 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 36 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 2 关注