为什么需要反射机制
Java反射机制是:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。这种动态获取的信息以及动态调用对象的方法的功能称为反射机制。
所以如果能够在运行时拿到Class对象,就可以生成java对象并进行调用。
反射赋予了jvm动态编译的能力。动态编译可以最大限度的体现Java的灵活性(多态)。否则类的元信息只能通过静态编译的形式实现(在编译期确定类型,绑定对象),而不能实现动态编译(在运行期确定类型,绑定对象)。也就是说在编译以后,程序在运行时的行为就是固定的了,如果要在运行时改变程序的行为,就需要动态编译,在Java中就需要反射机制。
- 情景一: 有的类无法使用 new 一个对象的方式来实例化。
- 情景二:有的类可以在用到时再动态加载到jvm中,这样可以减少jvm的启动时间,同时更重要的是可以动态的加载需要的对象(多态)。
- 情景三:避免将程序写死到代码中。
反射的缺点:
- 性能开销:由于反射涉及动态解析的类型,因此无法执行某些 Java 虚拟机优化。
- 破坏封装性: 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
- 内部曝光: 由于反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,所以反射的使用可能会导致意想不到的副作用,这可能会导致代码功能失常并可能破坏可移植性。
代码实现
首先构造一个类 Person 来实现反射,这个类是我们要通过反射来调用的类
1 | package com.gao.reflect; |
1. 获取class 对象
应用反射的第一步是要拿到该类的静态属性class 然后通过拿到类的方法和属性。
共有三种方法获取:通过实例的方法、通过类的静态属性、通过字节码
1 | public class MyReflection { |
2. 获取构造函数并创建对象
之后我们都将通过字节码文件,来获取 class 对象。
可以由两种划分:
- 私有构造函数/公有构造函数
- 单个构造函数/构造函数集合
在获取单个带参构造函数的时候,需要指定参数个数和数据类型对应的字节码文件对象(Class)。
对于私有方法还可以通过.setAccessible(true) 来访问。
通过反射调用构造函数,是把实例对象和参数交给函数对象的invoke 来做
1 |
|
3. 获取属性并赋值
属性可以直接通过名字直接访问。
通过反射给属性赋值,是把对象和属性值交给 属性域的 set。
1 | import java.lang.reflect.Constructor; |
4. 访问成员方法
同构造方法一样,也是通过 invoke 的函数来调用反射得到的成员方法。
对于有返回值的方法,invoke 会返回函数调用的返回值。
1 | import java.lang.reflect.Constructor; |
5. 越过泛型检查
1 | import java.lang.reflect.InvocationTargetException; |
参考链接: