这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战
反射机制
概念
指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制
反射API
实现 Java 反射机制的类都位于 java.lang.reflect 包中,java.lang.Class 类是 Java 反射机制 API 中的核心类
Class类
反射的核心类,可以获取类的属性,方法等信息。
Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型和 void。Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的。
获取 Class 对象的方式
-
Class.forName("全类名")源代码阶段,它能将字节码文件加载进内存中,然后返回
Class对象,多用于配置文件中,将类名定义在配置文件中,通过读取配置文件来加载类。 -
类名.class类对象阶段,通过类名的
class属性来获取,多用于参数的传递。 -
对象.getClass()运行时阶段,
getClass()定义在Object类中,表明所有类都能使用该方法,多用于对象的获取字节码的方式。
同一个字节码文件(*.class)在一次运行过程中只会被加载一次。
| 类型 | 访问方法 | 返回值类型 | 说明 |
|---|---|---|---|
| 包路径 | getPackage() | Package 对象 | 获取该类的存放路径 |
| 类名称 | getName() | String 对象 | 获取该类的名称 |
| 继承类 | getSuperclass() | Class 对象 | 获取该类继承的类 |
| 实现接口 | getlnterfaces() | Class 型数组 | 获取该类实现的所有接口 |
| 构造方法 | getConstructors() | Constructor 型数组 | 获取所有权限为 public 的构造方法 |
| getDeclaredContruectors() | Constructor 对象 | 获取当前对象的所有构造方法 | |
| 方法 | getMethods() | Methods 型数组 | 获取所有权限为 public 的方法 |
| getDeclaredMethods() | Methods 对象 | 获取当前对象的所有方法 | |
| 成员变量 | getFields() | Field 型数组 | 获取所有权限为 public 的成员变量 |
| getDeclareFileds() | Field 对象 | 获取当前对象的所有成员变量 | |
| 内部类 | getClasses() | Class 型数组 | 获取所有权限为 public 的内部类 |
| getDeclaredClasses() | Class 型数组 | 获取所有内部类 | |
| 内部类的声明类 | getDeclaringClass() | Class 对象 | 如果该类为内部类,则返回它的成员类,否则返回 null |
java.lang.reflect 包
java.lang.reflect 包提供了反射中用到类,主要的类说明如下:
- Constructor 类:提供类的构造方法信息。
- Field 类:提供类或接口中成员变量信息。
- Method 类:提供类或接口成员方法信息。
- Array 类:提供了动态创建和访问 Java 数组的方法。
- Modifier 类:提供类和成员访问修饰符信息。
Constructor 构造方法
创建的每个 Constructor 对象表示一个构造方法,然后利用 Constructor 对象的方法操作构造方法
| 方法名称 | 说明 |
|---|---|
| isVarArgs() | 查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回 false |
| getParameterTypes() | 按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型 |
| getExceptionTypes() | 以 Class 数组的形式获取该构造方法可能抛出的异常类型 |
| newInstance(Object … initargs) | 通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示 采用默认无参的构造方法 |
| setAccessiable(boolean flag) | 如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对 象 |
| getModifiers() | 获得可以解析出该构造方法所采用修饰符的整数 |
Modifier 类和成员访问修饰符
该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以字符串的形式获得所有修饰符
| 静态方法名称 | 说明 |
|---|---|
| isStatic(int mod) | 如果使用 static 修饰符修饰则返回 true,否则返回 false |
| isPublic(int mod) | 如果使用 public 修饰符修饰则返回 true,否则返回 false |
| isProtected(int mod) | 如果使用 protected 修饰符修饰则返回 true,否则返回 false |
| isPrivate(int mod) | 如果使用 private 修饰符修饰则返回 true,否则返回 false |
| isFinal(int mod) | 如果使用 final 修饰符修饰则返回 true,否则返回 false |
| toString(int mod) | 以字符串形式返回所有修饰符 |
Method 方法
| 静态方法名称 | 说明 |
|---|---|
| getName() | 获取该方法的名称 |
| getParameterType() | 按照声明顺序以 Class 数组的形式返回该方法各个参数的类型 |
| getReturnType() | 以 Class 对象的形式获得该方法的返回值类型 |
| getExceptionTypes() | 以 Class 数组的形式获得该方法可能抛出的异常类型 |
| invoke(Object obj,Object...args) | 利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型 |
| isVarArgs() | 查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 false |
| getModifiers() | 获得可以解析出该方法所采用修饰符的整数 |
Field 成员变量
| 方法名称 | 说明 |
|---|---|
| getName() | 获得该成员变量的名称 |
| getType() | 获取表示该成员变量的 Class 对象 |
| get(Object obj) | 获得指定对象 obj 中成员变量的值,返回值为 Object 类型 |
| set(Object obj, Object value) | 将指定对象 obj 中成员变量的值设置为 value |
| getlnt(0bject obj) | 获得指定对象 obj 中成员类型为 int 的成员变量的值 |
| setlnt(0bject obj, int i) | 将指定对象 obj 中成员变量的值设置为 i |
| setFloat(Object obj, float f) | 将指定对象 obj 中成员变量的值设置为 f |
| getBoolean(Object obj) | 获得指定对象 obj 中成员类型为 boolean 的成员变量的值 |
| setBoolean(Object obj, boolean b) | 将指定对象 obj 中成员变量的值设置为 b |
| getFloat(Object obj) | 获得指定对象 obj 中成员类型为 float 的成员变量的值 |
| setAccessible(boolean flag) | 此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量 |
| getModifiers() | 获得可以解析出该方法所采用修饰符的整数 |
优缺点
优点
- 在程序运行过程中可以操作类对象,增加了程序的灵活性;
- 解耦,从而提高程序的可扩展性,提高代码的复用率,方便外部调用;
- 对于任何一个类,当知道它的类名后,就能够知道这个类的所有属性和方法;而对于任何一个对象,都能够调用它的一个任意方法。
缺点
- 性能问题:Java 反射中包含了一些动态类型,JVM 无法对这些动态代码进行优化,因此通过反射来操作的方式要比正常操作效率更低。
- 安全问题:使用反射时要求程序必须在一个没有安全限制的环境中运行,如果程序有安全限制,就不能使用反射。
- 程序健壮性:反射允许代码执行一些平常不被允许的操作,破坏了程序结构的抽象性,导致平台发生变化时抽象的逻辑结构无法被识别。