Java 反射详解
什么是反射?
反射是 Java 的动态特性,允许在运行时获取类的信息(属性、方法、构造器)并动态操作它们。
正常情况下,我们在编译时就知道要操作哪个类。反射让我们在运行时才决定操作哪个类。
获取 Class 对象的三种方式
// 方式1:通过类的 class 属性(最常用)
Class<?> clazz1 = Cat.class;
// 方式2:通过对象的 getClass() 方法
Cat cat = new Cat("三花");
Class<?> clazz2 = cat.getClass();
// 方式3:通过 Class.forName("全限定类名")
Class<?> clazz3 = Class.forName("com.example.Cat");
反射操作构造器
获取构造器
import java.lang.reflect.Constructor;
// 获取所有 public 构造器
Constructor<?>[] constructors = clazz.getConstructors();
// 获取所有构造器(包括 private)
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
// 获取指定构造器
Constructor<?> constructor = clazz.getConstructor(String.class); // 参数类型
使用构造器创建对象
// 1. 获取构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
// 2. 暴力破解:跳过权限检查(访问 private 构造器)
constructor.setAccessible(true);
// 3. 用构造器初始化对象
Object obj = constructor.newInstance("三花"); // 传入构造器参数
完整示例
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> clazz = Class.forName("com.example.Cat");
// 获取构造器(String 参数的构造器)
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
// 暴力访问
constructor.setAccessible(true);
// 创建对象
Cat cat = (Cat) constructor.newInstance("三花");
System.out.println(cat.getName()); // 输出: 三花
}
}
反射操作成员变量
获取成员变量
import java.lang.reflect.Field;
// 获取所有 public 字段
Field[] fields = clazz.getFields();
// 获取所有字段(包括 private)
Field[] declaredFields = clazz.getDeclaredFields();
// 获取指定字段
Field nameField = clazz.getDeclaredField("name");
赋值和取值
// 假设有一个 Cat 类,有 private String name 字段
Cat cat = new Cat();
// 获取字段
Field nameField = clazz.getDeclaredField("name");
// 暴力访问(private 字段需要)
nameField.setAccessible(true);
// 赋值
nameField.set(cat, "小白"); // cat.name = "小白"
// 取值
String name = (String) nameField.get(cat); // 读取 cat.name
完整示例
public class FieldDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Cat.class;
Cat cat = (Cat) clazz.getDeclaredConstructor().newInstance();
// 获取所有字段并输出
for (Field field : clazz.getDeclaredFields()) {
System.out.println("字段名: " + field.getName() +
", 类型: " + field.getType());
}
// 操作 name 字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(cat, "小白");
System.out.println("name = " + nameField.get(cat));
}
}
反射操作成员方法
获取成员方法
import java.lang.reflect.Method;
// 获取所有 public 方法(不包括继承的 Object 方法)
Method[] methods = clazz.getMethods();
// 获取所有方法(包括 private)
Method[] declaredMethods = clazz.getDeclaredMethods();
// 获取指定方法(方法名 + 参数类型)
Method eatMethod = clazz.getDeclaredMethod("eat");
Method playMethod = clazz.getDeclaredMethod("play", String.class); // play(String)
执行方法
Cat cat = new Cat();
// 获取方法
Method eatMethod = clazz.getDeclaredMethod("eat");
// 暴力访问
eatMethod.setAccessible(true);
// 执行方法(invoke:激活/调用)
// 无参数方法
eatMethod.invoke(cat);
// 有参数方法
Method playMethod = clazz.getDeclaredMethod("play", String.class);
playMethod.invoke(cat, "毛球"); // cat.play("毛球")
完整示例
public class MethodDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Cat.class;
Cat cat = (Cat) clazz.getDeclaredConstructor().newInstance();
// 执行 eat 方法
Method eatMethod = clazz.getDeclaredMethod("eat");
eatMethod.setAccessible(true);
eatMethod.invoke(cat);
// 执行 play 方法
Method playMethod = clazz.getDeclaredMethod("play", String.class);
playMethod.setAccessible(true);
playMethod.invoke(cat, "毛球");
}
}
反射的应用场景
| 场景 | 说明 |
|---|---|
| Spring 依赖注入 | 通过反射读取 @Autowired 注解,自动注入 Bean |
| MyBatis | 读取映射文件,自动将 ResultSet 映射到对象 |
| AOP | 动态代理,在方法前后增强逻辑(如 字段填充.md 中的 AutoFill) |
| Jackson 反序列化 | 将 JSON 字符串转换为 Java 对象 |
| Spring MVC | 根据请求路径自动调用对应的 Controller 方法 |
| 工厂模式 | 配置文件 + 反射实现松耦合的对象创建 |
反射的优缺点
优点
- 动态性:在运行时决定操作哪个类,提高灵活性
- 解耦:配合配置文件,实现松耦合设计
缺点
- 性能开销:反射涉及类型检查和权限检查,比直接调用慢
- 安全问题:可以访问 private 成员,破坏封装性
- 复杂度高:代码可读性差,调试困难
常用 API 速查表
| 分类 | 方法 | 说明 |
|---|---|---|
| Class 获取 | Class.forName("类名") | 通过全限定名获取 |
类名.class | 通过 class 属性获取 | |
对象.getClass() | 通过对象获取 | |
| 构造器 | getDeclaredConstructors() | 获取所有构造器 |
getDeclaredConstructor(参数类型...) | 获取指定构造器 | |
newInstance(参数...) | 创建对象 | |
| 字段 | getDeclaredFields() | 获取所有字段 |
getDeclaredField("字段名") | 获取指定字段 | |
set(对象, 值) / get(对象) | 赋值/取值 | |
| 方法 | getDeclaredMethods() | 获取所有方法 |
getDeclaredMethod("方法名", 参数类型...) | 获取指定方法 | |
invoke(对象, 参数...) | 执行方法 |