反射
1.反射允许对类中成员变量,成员方法和构造方法的信息进行编程访问。
2.反射的作用:
- 获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑
- 结合配置文件,动态地创建对象并调用方法
3.获取class对象的三种方式:
- Class.forName("全类名"),Class本身也是Java中一个类,forName是其静态方法。全类名是包名 + 类名,也可以直接打开需要获取的类,选中类名右键 -> Copy/Paste Special -> CopyReference,这种方式较为常用
- 类名.class(一般当作参数使用,比如同步代码块中的锁)
- 对象.getClass();(当已经有该类对象才使用)
- 不同阶段使用不同的方法,在源代码阶段(还在写该类的代码阶段),代码没有加载到内存中,此时使用第一种;在加载阶段(该类代码已经加载到了内存当中),使用第二种方式;在运行阶段,使用第三种方式。实话说这里没有听的很懂,个人认为不用严格遵循
4.利用反射获取构造方法:
- 首先需要获取到对应类的Class(字节码文件)类对象
- 有s即为所有
- 有declared即为忽略修饰符
- 获得单个构造方法的时候,需要往方法中传入对应构造方法中形参类型的Class(字节码文件)对象,比如一个方法的形参为String类型以及int类型两个参数,传入时就需要传入String.Class和int.Class
- Constructor类的成员方法
方法名 | 说明 |
int getModifiers() | 获取当前构造方法修饰符对应的常量字段值 |
Parameter[] getParameters() | 获取当前构造方法的所有参数类型 |
void setAccessible(boolean) | 暴力反射:传入true时临时取消权限的校验 |
Object newInStance(...) | 创建一个对应类的对象(其实是Object,需要强转才能真正是对应类),参数需要和当前构造方法的个数与类型一致,但是如果是私有或者protected则需要暴力反射后才能创建,否则报错 |
5.利用反射获取成员变量
- 首先需要获取到对应类的Class(字节码文件)类对象
- 有s即为所有
- 有declared即为忽略修饰符
- 同样的获取到的成员变量也可以使用构造方法的getModifiers(),setAccessible(boolean),返回值以及用法都是一样的
- Filed常用的成员方法
方法名 | 说明 |
int getModifiers() | 获取当前构造方法修饰符对应的常量字段值 |
void setAccessible(boolean) | 暴力反射:传入true时临时取消权限的校验 |
void set(对应的类对象,当前的成员变量要修改成的值) | 因为当前是成员变量,因此第二个参数一定是对应对象的当前成员变量修改后的值 |
String getName() | 获取成员变量的名字 |
String get(当前成员变量对应的类) | 获取当前对象成员变量的值 |
6.利用反射获取成员方法
- 首先需要获取到对应类的Class(字节码文件)类对象
- 有s即为所有
- 有declared即为忽略修饰符
- 如果是获取所有公共成员方法,会返回当前类以及父类的所有公共成员方法
- 如果是获取所有成员方法,则只会返回当前类的所有成员方法
- 获取单个成员方法时,需要传入成员方法的字符串名称,以及对应成员方法的形参的字节码文件,因为有可能有方法的重载
- Method的一些成员方法:
方法名 | 说明 |
int getModifiers() | 获取当前构造方法修饰符对应的常量字段值 |
Parameter[] getParameters() | 获取方法的形参 |
String getName() | 获取方法的名字 |
Class<?>[] getExceptionTypes() | 获取方法抛出的异常 |
void setAccessible(boolean) | 暴力反射:传入true时临时取消权限的校验 |
Object invoke(Object obj...) | 运行方法 |
Object invoke(Object obj...),如果要运行的方法是私有或者protected的,需要先取消权限校验,也就是setAccessible。方法中第一个参数是当前获取的成员方法所在的类的对象,比如说当前成员方法是属于Student类的,传入的就是Student类的对象。其他形参就是当前成员方法的形参,需要传入实参。返回值Object是当前成员方法的返回值,但是是Object类型的,如果想要实际方法的返回值类型,还需要进行强转。