java反射的二三事

一、什么是反射机制

简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息,诸如:类变量,构造函数,方法,修饰符。

二、反射机制的优点与缺点

优点:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多 态的应用,有以降低类之间的藕合性。

缺点:对性能有影响

三、利用反射机制能获得什么信息

一句话,类中有什么信息,它就可以获得什么信息,不过前提是得知道类的名字,要不就没有后文了

首先得根据传入的类的全名来创建Class对象。

Class c=Class.forName("className");注明:className必须为全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo;

Object obj=c.newInstance();//创建对象的实例

OK,有了对象就什么都好办了,想要什么信息就有什么信息了。

获得构造函数的方法

Constructor getConstructor(Class[] params)//根据指定参数获得public构造器

Constructor[] getConstructors()//获得public的所有构造器

Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器

Constructor[] getDeclaredConstructors()//获得public的所有构造器

获得类方法的方法

Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法

Method[] getMethods()//获得所有的public方法

Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法

Method[] getDeclaredMethods()//获得所以的public和非public方法

获得类中属性的方法

Field getField(String name)//根据变量名得到相应的public变量

Field[] getFields()//获得类中所以public的方法

Field getDeclaredField(String name)//根据方法名获得public和非public变量

Field[] getDeclaredFields()//获得类中所有的public和非public方法

四、反射适用场景

1、Java的反射机制在做基础框架的时候非常有用,有一句话这么说来着:反射机制是很多Java框架的基石,而一般应用层面很少用。

2.当你做一个软件可以安装插件的功能,你连插件的类型名称都不知道,你怎么实例化这个对象呢?因为程序是支持插件的(第三方的),在开发的时候并不知道 。所以无法在代码中 New出来 ,但反射可以,通过反射,动态加载程序集,然后读出类,检查标记之后再实例化对象,就可以获得正确的类实例。

3.在编码阶段不知道那个类名,要在运行期从配置文件读取类名, 这时候就没有办法硬编码new ClassName(),而必须用到反射才能创建这个对象.反射的目的就是为了扩展未知的应用。比如你写了一个程序,这个程序定义了一些接口,只要实现了这些接口的dll都可以作为插件来插入到这个程序中。那么怎么实现呢?就可以通过反射来实现。就是把dll加载进内存,然后通过反射的方式来调用dll中的方法。很多工厂模式就是使用的反射。

五、反射影响性能的原因

反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多,其次由于反射是本地方法调用,让JVM无法优化,反射方法调用还有验证过程和参数问题,参数需要装箱拆箱、需要组装成Object[]形式、异常的包装等等问题。。。

六、反射性能优化

1、setAccessible(true)

使用了method.setAccessible(true)后 性能有了20倍的提升,实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问,由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的

JDK API中的解释 :

AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。

在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。

2、jit,不去了解反射优化,还真不知道JIT是什么东西

如果你在jdk6上跑,且如果你反射的目标方法是getter/setter methods的话,记得加上配置:-XX:-UseFastEmptyMethods -XX:-UseFastAccessorMethods , 这两个配置的关闭是为了让accessor methods能够被jit; jdk7以上不需要设置这两个配置

即时编译,又译及时编译、实时编译,动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态直译。静态编译的程序在执行前全部被翻译为机器码,而直译执行的则是一句一句边运行边翻译。 即时编译器则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。 即时编译器有两种类型,一是字节码翻译,二是动态编译翻译。 微软的.NET Framework,还有绝大多数的Java实现,都依赖即时翻译以提供高速的代码执行

如果你在jdk6上跑,且如果你反射的目标方法是getter/setter methods的话,记得加上配置:-XX:-UseFastEmptyMethods -XX:-UseFastAccessorMethods , 这两个配置的关闭是为了让accessor methods能够被jit; jdk7以上不需要设置这两个配置

3、缓存(推荐使用org.codehaus.groovy.reflection.ReflectionCache这个类)

该类在类库groovy-all-2.4.6.jar可以找到

这个优化是一般反射优化的基本解决方案,就是把所有经常用到的反射对象缓存起来,在下次用到的时候直接从缓存中获取。

4.系统启动阶段使用反射。

将反射得到元数据保存起来,使用时,只需从内存中调用即可,hotspot虚拟机会对执行次数较多的方法进行优化(例如使用jit技术)

5、使用高性能的反射类库ReflectASM(该类库无法反射私有方法和变量)

另外也推荐spring自带的ReflectionUtils工具类

章后建议:在业务开发时尽量远离反射,首先是代码可读性与工具支持。打开熟悉的IDE,寻找你的Java代码的内部依赖,很容易吧。现在,使用反射来替换掉你的代码然后再试一下,结果如何呢?如果通过反射来修改已经封装好的对象状态,那么结果将会变得更加不可控。其次JIT对反射的优化程度是不同的,有些优化时间会更长一些,而有些甚至是无法应用优化。因此,有时反射的性能损失可以达到几个数量级的差别。最后我觉得在业务代码中能合理(直接)使用反射的场景是通过AOP

原文发布于微信公众号 - Linyb极客之路(gh_c420b2cf6b47)

原文发表时间:2018-02-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏V站

如何提高PHP编程效率,提升程序编译质量(53条)

用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串...

1645
来自专栏java一日一条

Java反射在JVM的实现

反射使程序代码能够接入装载到JVM中的类的内部信息,允许在编写与执行时,而不是源代码中选定的类协作的代码,是以开发效率换运行效率的一种手段。这使反射成为构建灵活...

2133
来自专栏章鱼的慢慢技术路

Go语言相关练习_选择题(2)

go语言中字符串是UTF-8编码并存储的,它语言不定长的字节,所以它不支持下标操作,因为没一个下标操作代表的是固定长度的字节,所以不能对字符串中某个字符单独赋值...

1022
来自专栏Python专栏

Python | 19个优雅的Python编程技巧

http://lovesoo.org/pythonic-python-programming.html

2913
来自专栏栗霖积跬步之旅

java多线程编程核心技术——第五章总结

定时器Timer的使用   在JDK中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务。 ?   Timer类的主要作用是设置计划任务,...

1999
来自专栏企鹅号快讯

PHP中被忽略的性能优化利器:生成器

如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生。但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP5.5.0才引入的功能,也...

38914
来自专栏老付的网络博客

程序如何运行的

在写代码的时候,我们直接在没有编译报错的时候,直接点击运行后,ide会直接把程序的结果输出到控制台上,代码如下:

1935
来自专栏林德熙的博客

dotnet core 编程规范

本文实际只是翻译 .NET Core foundational libraries 官方文档的编码风格。

912
来自专栏从流域到海域

堆和栈的区别

堆(heap)和栈(stack) 在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构。堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(...

2157
来自专栏老马说编程

计算机程序的思维逻辑 (第7节更新) - 再谈乱码恢复

在第6节和第7节,我们讨论了文本的二进制编码、乱码、以及恢复,第6节受到了很多读者的一致好评,但第7节有读者反馈解说的不太透彻,希望再详细一点,本文就是对第7节...

2076

扫码关注云+社区

领取腾讯云代金券