开篇概览:反射的核心价值
反射(Reflection) 是 Java 在运行时动态分析、操作类与对象的能力。它允许程序在运行时:
- 获取类的完整结构(字段、方法、构造器等);
- 动态创建对象;
- 动态调用方法、访问字段;
- 突破访问控制(如访问
private成员)。
反射是许多高级框架(如 Spring、Hibernate、JUnit)的底层基础,也是实现插件化、动态代理、ORM 映射等技术的关键。
⚠️ 重要前提:
- 反射操作性能较低(比直接调用慢数倍);
- 破坏封装性,应谨慎使用;
- 仅在编译期无法确定类型时使用(如框架开发、通用工具)。
一、Class 类:反射的入口
java.lang.Class 是反射的核心类,代表运行时的类元数据。每个类在 JVM 中有且仅有一个 Class 对象。
1.1 获取 Class 对象的三种方式
| 方式 | 说明 | 示例 |
|---|---|---|
类名.class | 编译期已知类型 | String.class |
对象.getClass() | 通过实例获取 | "hello".getClass() |
Class.forName("全限定类名") | 动态加载(常用) | Class.forName("java.lang.String") |
1.2 示例:获取 Class 对象
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1:通过类字面量(推荐,简洁安全)
Class<String> stringClass1 = String.class;
// 方式2:通过对象实例
String str = "Hello";
Class<? extends String> stringClass2 = str.getClass();
// 方式3:通过全限定类名(动态加载,可能抛出 ClassNotFoundException)
Class<?> stringClass3 = Class.forName("java.lang.String");
// 验证三个 Class 对象是否相同(同一类在 JVM 中只有一个 Class 实例)
System.out.println("方式1 == 方式2: " + (stringClass1 == stringClass2)); // true
System.out.println("方式1 == 方式3: " + (stringClass1 == stringClass3)); // true
// 获取类的基本信息
System.out.println("类名(含包): " + stringClass1.getName()); // java.lang.String
System.out.println("简单类名: " + stringClass1.getSimpleName()); // String
System.out.println("是否为接口: " + stringClass1.isInterface()); // false
System.out.println("是否为数组: " + stringClass1.isArray()); // false
}
}
✅ 关键点:
Class.forName()会初始化类(执行 static 块);- 若只需加载类而不初始化,使用
Class.forName(name, false, loader)。
二、获取类的成员信息
通过 Class 对象可获取类的构造器、字段、方法等元数据。
2.1 核心方法概览
| 获取内容 | 方法 | 返回类型 |
|---|---|---|
| 构造器 | getConstructors() / getDeclaredConstructors() | Constructor<?>[] |
| 字段 | getFields() / getDeclaredFields() | Field[] |
| 方法 | getMethods() / getDeclaredMethods() | Method[] |
🔑
getXXX()vsgetDeclaredXXX():
getXXX():仅返回public成员(包括继承的);getDeclaredXXX():返回 所有声明的成员(含private/protected,但不包括继承的)。
2.2 示例:分析类的结构(详细中文注释)
import java.lang.reflect.*;
// 定义一个测试类(含 private 成员)
class Person {
public String name;
private int age;
protected String email;
public Person() {}
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, I'm " + name);
}
private void setAge(int age) {
this.age = age;
}
}
public class ReflectionAnalysisDemo {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
// 1. 获取所有 public 构造器(包括继承的,但 Object 无 public 构造器)
System.out.println("=== public 构造器 ===");
Constructor<?>[] publicConstructors = personClass.getConstructors();
for (Constructor<?> c : publicConstructors) {
System.out.println("构造器: " + c);
}
// 输出: public Person()
// 2. 获取所有声明的构造器(含 private)
System.out.println("\n=== 所有声明的构造器 ===");
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> c : declaredConstructors) {
System.out.println("构造器: " + c);
}
// 输出:
// public Person()
// private Person(java.lang.String,int)
// 3. 获取所有 public 字段(包括继承的)
System.out.println("\n=== public 字段 ===");
Field[] publicFields = personClass.getFields();
for (Field f : publicFields) {
System.out.println("字段: " + f.getType().getSimpleName() + " " + f.getName());
}
// 输出: String name
// 4. 获取所有声明的字段(含 private/protected)
System.out.println("\n=== 所有声明的字段 ===");
Field[] declaredFields = personClass.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println("字段: " + f.getType().getSimpleName() + " " + f.getName() +
" (修饰符: " + Modifier.toString(f.getModifiers()) + ")");
}
// 输出:
// String name (修饰符: public)
// int age (修饰符: private)
// String email (修饰符: protected)
// 5. 获取所有 public 方法(包括继承的 Object 方法)
System.out.println("\n=== public 方法 ===");
Method[] publicMethods = personClass.getMethods();
for (Method m : publicMethods) {
System.out.println("方法: " + m.getName());
}
// 输出: sayHello, wait, equals, toString, hashCode 等
// 6. 获取所有声明的方法(不含继承的)
System.out.println("\n=== 所有声明的方法 ===");
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println("方法: " + m.getName() +
" (修饰符: " + Modifier.toString(m.getModifiers()) + ")");
}
// 输出:
// sayHello (修饰符: public)
// setAge (修饰符: private)
}
}
✅ 关键点:
- 使用
Modifier.toString()可读化修饰符;getMethods()包含从Object继承的方法(如toString)。
三、通过反射操作对象
3.1 创建对象
方式1:调用无参构造器
// 使用 Class.newInstance()(已废弃,Java 9+)
// Person p = (Person) personClass.newInstance();
// 推荐方式:通过 Constructor
Constructor<Person> constructor = personClass.getConstructor();
Person person = constructor.newInstance();
方式2:调用带参构造器(含 private)
// 获取 private 构造器
Constructor<Person> privateConstructor = personClass.getDeclaredConstructor(String.class, int.class);
// 突破访问控制
privateConstructor.setAccessible(true);
Person person2 = privateConstructor.newInstance("张三", 25);
3.2 调用方法
调用 public 方法
// 获取 public 方法
Method sayHelloMethod = personClass.getMethod("sayHello");
// 调用方法(第一个参数是对象实例)
sayHelloMethod.invoke(person2); // 输出: Hello, I'm 张三
调用 private 方法
// 获取 private 方法
Method setAgeMethod = personClass.getDeclaredMethod("setAge", int.class);
// 突破访问控制
setAgeMethod.setAccessible(true);
// 调用 private 方法
setAgeMethod.invoke(person2, 30);
3.3 访问字段
访问 public 字段
// 直接访问 public 字段
Field nameField = personClass.getField("name");
nameField.set(person2, "李四"); // 设置值
String name = (String) nameField.get(person2); // 获取值
System.out.println("姓名: " + name); // 李四
访问 private 字段
// 访问 private 字段
Field ageField = personClass.getDeclaredField("age");
ageField.setAccessible(true); // 突破访问控制
ageField.set(person2, 28);
int age = (int) ageField.get(person2);
System.out.println("年龄: " + age); // 28
四、完整示例:反射综合应用
import java.lang.reflect.*;
// 测试类
class Student {
private String name;
private int score;
public Student() {}
public void study() {
System.out.println(name + " 正在学习,当前分数: " + score);
}
private void updateScore(int newScore) {
this.score = newScore;
System.out.println("分数已更新为: " + score);
}
}
public class FullReflectionDemo {
public static void main(String[] args) throws Exception {
// 1. 获取 Class 对象
Class<Student> studentClass = Student.class;
// 2. 创建对象(调用无参构造器)
Student student = studentClass.getConstructor().newInstance();
System.out.println("对象创建成功: " + student);
// 3. 设置 private 字段
Field nameField = studentClass.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(student, "王五");
Field scoreField = studentClass.getDeclaredField("score");
scoreField.setAccessible(true);
scoreField.set(student, 85);
// 4. 调用 public 方法
Method studyMethod = studentClass.getMethod("study");
studyMethod.invoke(student); // 王五 正在学习,当前分数: 85
// 5. 调用 private 方法
Method updateScoreMethod = studentClass.getDeclaredMethod("updateScore", int.class);
updateScoreMethod.setAccessible(true);
updateScoreMethod.invoke(student, 92); // 分数已更新为: 92
// 6. 验证字段值是否更新
int currentScore = (int) scoreField.get(student);
System.out.println("最终分数: " + currentScore); // 92
}
}
✅ 输出:
对象创建成功: reflection.Student@... 王五 正在学习,当前分数: 85 分数已更新为: 92 最终分数: 92
五、反射的局限性与最佳实践
⚠️ 局限性
- 性能开销大:方法调用比直接调用慢 2-3 倍;
- 破坏安全性:可绕过访问控制(需 SecurityManager 限制);
- 代码脆弱:依赖字符串(如方法名),重构易出错;
- 泛型擦除:运行时无法获取泛型实际类型。
✅ 最佳实践
- 仅在必要时使用:如框架开发、通用工具类;
- 缓存反射对象:避免重复获取
Method/Field; - 优先使用
getDeclaredXXX()+setAccessible(true); - 处理异常:
ReflectiveOperationException(含ClassNotFoundException、NoSuchMethodException等); - 考虑替代方案:如接口、Lambda、注解处理器。
六、总结:反射核心能力全景
| 能力 | 方法 | 用途 |
|---|---|---|
| 获取 Class | 类.class, 对象.getClass(), Class.forName() | 反射入口 |
| 创建对象 | Constructor.newInstance() | 动态实例化 |
| 调用方法 | Method.invoke() | 动态方法调用 |
| 访问字段 | Field.get() / set() | 动态读写属性 |
| 突破访问控制 | setAccessible(true) | 访问 private 成员 |
📌 核心思想:
“反射是 Java 的‘自省’能力,让程序在运行时理解自身结构。”
它是一把双刃剑——用得好可构建灵活框架,用得滥则导致代码脆弱。掌握反射,是深入理解 Java 语言与 JVM 机制的关键一步。
1286

被折叠的 条评论
为什么被折叠?



