什么是反射?
在 Java 中,反射(Reflection) 是指程序在运行时可以访问、检测和修改自身结构及行为的能力。简单来说,就是 Java 代码可以在运行时 “看透” 类的内部信息(如类名、方法、字段等),并动态调用类的方法或操作类的字段,而无需在编译期就知道类的具体信息。
反射的核心原理
Java 的类加载机制会将.class
字节码文件加载到 JVM 中,并生成一个对应的Class
对象(每个类在 JVM 中只有一个Class
对象)。反射正是通过操作这个Class
对象,来获取类的元数据(如构造器、方法、字段等),并动态创建对象或调用方法。
反射的核心类(位于java.lang.reflect
包)
Class
:代表类的字节码对象,是反射的入口。Constructor
:代表类的构造方法,用于创建对象。Method
:代表类的方法,用于动态调用方法。Field
:代表类的字段(成员变量),用于操作字段的值。
反射的基本使用步骤
以操作一个简单的User
类为例:
public class User {
private String name;
private int age;
public User() {} // 无参构造
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, " + name);
}
private void setAge(int age) {
this.age = age;
}
}
1. 获取Class
对象(反射的入口)
有 3 种方式获取Class
对象:
// 方式1:通过类名.class
Class<User> clazz1 = User.class;
// 方式2:通过对象.getClass()
User user = new User();
Class<? extends User> clazz2 = user.getClass();
// 方式3:通过Class.forName("全类名")(最常用,适合动态加载)
Class<?> clazz3 = Class.forName("com.example.User");
2. 动态创建对象
通过Constructor
创建对象(支持调用私有构造):
// 获取无参构造并创建对象
Constructor<?> constructor = clazz.getConstructor();
User user1 = (User) constructor.newInstance();
// 获取有参构造并创建对象(参数为构造方法的参数类型)
Constructor<?> constructor2 = clazz.getConstructor(String.class, int.class);
User user2 = (User) constructor2.newInstance("张三", 20);
3. 动态调用方法
通过Method
调用方法(支持调用私有方法):
// 调用公共方法sayHello()
Method sayHelloMethod = clazz.getMethod("sayHello");
sayHelloMethod.invoke(user2); // 输出:Hello, 张三
// 调用私有方法setAge(int)
Method setAgeMethod = clazz.getDeclaredMethod("setAge", int.class);
setAgeMethod.setAccessible(true); // 暴力访问私有方法(关闭权限检查)
setAgeMethod.invoke(user2, 25); // 调用后user2的age变为25
4. 动态操作字段
通过Field
操作字段(支持修改私有字段):
// 获取私有字段name并修改值
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 暴力访问私有字段
nameField.set(user2, "李四"); // 修改name为"李四"
// 获取字段值
String name = (String) nameField.get(user2);
System.out.println(name); // 输出:李四