反射
1.什么是反射
反射(Reflection)是一种 Java 程序运行期间的动态技术,可以在运行时(runtime)检査、修改其自身结构或行为。通过反射,程序可以访问、检测和修改它自己的类、对象、方法、属性等成员
2.反射的定义
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性, 既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
3.反射的用途
动态加载类:程序可以在运行时动态地加载类库中的类;
动态创建对象:反射可以基于类的信息,程序可以在运行时,动态创建对象实例;
调用方法:反射可以根据方法名称,程序可以在运行时,动态地调用对象的方法(即使方法在编写程序时还没有定义)
访问成员变量:反射可以根据成员变量名称,程序可以在运行时,访问和修改成员变量(反射可以访问私有成员变量)
运行时类型信息:反射允许程序在运行时,查询对象的类型信息,这对于编写通用的代码和库非常有用;
Spring 框架使用反射来自动装配组件,实现依赖注入;
MyBatis 框架使用反射来创建resultType 对象,封装数据查询结果
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量/类的属性 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
4.反射获取 Class
对象:
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取 Class 对象
Class<?> clazz = Class.forName("com.example.MyClass");
// 使用反射创建对象
Object obj = clazz.newInstance();
// 输出对象信息
System.out.println("对象创建成功: " + obj);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
我们首先通过 Class.forName("com.example.MyClass")
获取 Class
对象,然后调用 newInstance()
创建对象。需要注意的是,newInstance()
方法在 Java 9 以后被标记为弃用,建议使用 Constructor
的 newInstance()
方法。
5.通过反射创建对象
try {
Class<?> clazz = Class.forName("com.example.MyClass");
Constructor<?> constructor = clazz.getConstructor(); // 获取无参构造函数
Object obj = constructor.newInstance(); // 创建对象
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
6.使用 Java 反射机制获取和调用类的构造方法,访问私有构造方法并创建对象
假设我们有一个类 MyClass
,其中包含一个私有构造方法:
public class MyClass {
private MyClass() {
System.out.println("私有构造方法被调用");
}
public void display() {
System.out.println("MyClass 实例方法");
}
}
我们可以通过以下步骤来访问和调用这个私有构造方法:
import java.lang.reflect.Constructor;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取 Class 对象
Class<?> clazz = Class.forName("MyClass");
// 获取私有构造方法
Constructor<?> constructor = clazz.getDeclaredConstructor();
// 设置构造方法可访问
constructor.setAccessible(true);
// 使用私有构造方法创建对象
Object obj = constructor.newInstance();
// 调用实例方法
if (obj instanceof MyClass) {
((MyClass) obj).display();
}
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
- 获取
Class
对象:使用Class.forName("MyClass")
或其他方法来获取Class
对象。 - 获取构造方法:使用
getDeclaredConstructor()
获取指定的构造方法。由于是私有构造方法,我们需要使用getDeclaredConstructor()
而不是getConstructor()
。 - 设置可访问性:调用
setAccessible(true)
来绕过 Java 访问控制检查,使我们能够访问私有构造方法。 - 创建对象:使用
newInstance()
方法创建对象实例。 - 调用实例方法:如果需要,可以通过反射调用实例的方法。
7.通过反射,访问并使用成员方法
假设我们有一个类 MyClass
,其中包含一些方法:
public class MyClass {
private void privateMethod() {
System.out.println("调用了私有方法");
}
public void publicMethod(String message) {
System.out.println("调用了公共方法,消息: " + message);
}
}
反射访问并使用成员方法
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取 Class 对象
Class<?> clazz = Class.forName("MyClass");
// 创建 MyClass 实例
Object obj = clazz.getDeclaredConstructor().newInstance();
// 访问并调用私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true); // 设置方法可访问
privateMethod.invoke(obj); // 调用方法
// 访问并调用公共方法
Method publicMethod = clazz.getMethod("publicMethod", String.class);
publicMethod.invoke(obj, "Hello, Reflection!"); // 调用方法
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
-
获取
Class
对象:通过Class.forName("MyClass")
获取目标类的Class
对象。 -
创建实例:使用
getDeclaredConstructor().newInstance()
创建类的实例。 -
访问私有方法
:
- 使用
getDeclaredMethod("methodName")
获取私有方法对象。 - 使用
setAccessible(true)
绕过 Java 访问控制检查。 - 使用
invoke(obj)
调用方法。
- 使用
-
访问公共方法
:
- 使用
getMethod("methodName", parameterTypes)
获取公共方法对象。 - 使用
invoke(obj, parameters)
调用方法,并传入所需参数。
- 使用
这种方式允许你在运行时动态地调用方法,适用于需要灵活性和扩展性的场景。