反射
- 概念
在运行期,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java的反射机制。
简单来说,反射就是在运行期提供的动态地获取类信息(属性、方法)或调用对象的方法的功能。 - 反射API
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
/*
下面是我初学反射时做的笔记,应该可以帮到大家,代码我就不贴了。__biz=MzI4Njg5MDA5NA==&mid=2247486658&idx=1&sn=58e682f3b9c68def4f12c574afac0de3&chksm=ebd74dc3dca0c4d542aa7ef2f7944dba438a447ffc2b39650dc4362698c6a7acd32e1a5fe3dc&token=2140209384&lang=zh_CN#rd)
*/
想要使用反射,我先要得到class文件对象,其实也就是得到Class类的对象
Class类主要API:
成员变量 - Field
成员方法 - Constructor
构造方法 - Method
获取class文件对象的方式:
1:Object类的getClass()方法
2:数据类型的静态属性class
3:Class类中的静态方法:public static Class ForName(String className)
--------------------------------
获取成员变量并使用
1: 获取Class对象
2:通过Class对象获取Constructor对象
3:Object obj = Constructor.newInstance()创建对象
4:Field field = Class.getField("指定变量名")获取单个成员变量对象
5:field.set(obj,"") 为obj对象的field字段赋值
如果需要访问私有或者默认修饰的成员变量
1:Class.getDeclaredField()获取该成员变量对象
2:setAccessible() 暴力访问
---------------------------------
通过反射调用成员方法
1:获取Class对象
2:通过Class对象获取Constructor对象
3:Constructor.newInstance()创建对象
4:通过Class对象获取Method对象 ------getMethod("方法名");
5: Method对象调用invoke方法实现功能
如果调用的是私有方法那么需要暴力访问
1: getDeclaredMethod()
2: setAccessiable();
- 反射的优缺点
CS-Notes
反射的优点:
- 可扩展性 :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
- 类浏览器和可视化开发环境:一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
- 调试器和测试工具 : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API
定义,以确保一组测试中有较高的代码覆盖率。
反射的缺点:
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。
- 性能开销 :反射涉及了动态类型的解析,所以 JVM
无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。 - 安全限制 :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。
- 内部暴露 :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
- 反射的应用场景
- 反射最重要的用途就是开发各种通用框架。反射是框架的核心灵魂,动态代理设计模式采用了反射机制,还有 Spring、Hibernate 等框架也大量使用到了反射机制。比如 Spring框架、SpringMVC都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
- 将业务层抽象出一些平台能力,就可以用反射。
。。。。。。。。。。。。。。。。。。。。。。。。。。
5.注意事项
参考:安琪拉的博客 反射影响性能是因为运行时,程序需要动态解析的类型,例如Class.getDeclaredMethod 的时候方法方法的类型都是运行时检查,Java虚拟机也没办法优化,每次Method 执行都要从Class 类信息中加载,我们知道类的方法信息是放在单独的方法区的,对象在堆区,但是相比于反射带来的便利,如果不是高并发需要十分频繁的调用,反射的性能损耗可以忽略,并且反射性能损耗也有方法优化降低。
那如何降低反射的性能呢?
可以做缓存。 springframework 的 BeanUtils,在BeanUtils中实现了Method 的缓存。因此使用Spring framework提供的BeanUtils 包,反射性能影响很少。
在阿里巴巴开发规约有一条
【强制】避免用Apache Beanutils进行属性的copy。 说明:Apache
BeanUtils性能较差,可以使用其他方案比如Spring BeanUtils, Cglib BeanCopier,注意均是浅拷贝。
反例:[性能提升300%:Apache的BeanUtils的坑]
Apache BeanUtils 在类似copyProperties 方法实现机制上和Spring BeanUtils 略有不同,Apache BeanUtils 拷贝机制做了各种转换和解析逻辑, 导致性能变差,大家使用的时候注意区分。