Java 反射机制(Reflection)

一、什么是反射

反射(Reflection) 是 Java 提供的一种机制,它允许程序在运行时动态获取类的信息(方法、属性、构造方法等)以及操作对象本身。

通过反射可以:

  • 在运行时获取类的完整结构
  • 动态创建对象
  • 动态调用方法、访问字段
  • 实现解耦、插件式开发、框架封装等

反射是实现诸如 Spring、MyBatis、Junit、Tomcat、IDEA 插件系统 的核心技术之一。


二、反射的核心类

反射主要在 java.lang.reflectjava.lang.Class 包中,主要类包括:

类/接口 功能说明
Class<?> 表示类或接口的字节码对象
Field 表示类中的成员变量
Method 表示类中的方法
Constructor 表示类的构造方法
Modifier 表示修饰符工具类

三、反射的基本操作

1. 获取类的 Class 对象(3种方式)

1
2
3
4
5
6
7
8
9
java复制编辑// 方式一:通过类名.class
Class<?> clazz1 = String.class;

// 方式二:通过对象的 getClass()
String s = "hello";
Class<?> clazz2 = s.getClass();

// 方式三:通过 Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");

2. 创建对象

1
2
3
4
java复制编辑Class<?> clazz = Class.forName("java.lang.String");

// 调用无参构造方法
Object obj = clazz.getDeclaredConstructor().newInstance();

3. 获取并调用构造方法

1
2
3
java复制编辑Constructor<?> constructor = clazz.getConstructor(String.class);
Object strObj = constructor.newInstance("Hello");
System.out.println(strObj); // 输出 Hello

4. 获取方法并调用

1
2
3
java复制编辑Method method = clazz.getMethod("length");
int length = (int) method.invoke("Reflection");
System.out.println(length); // 输出 10

5. 获取成员变量并访问

1
2
3
4
5
6
7
8
9
10
11
java复制编辑public class Person {
private String name = "张三";
}

Class<?> clazz = Person.class;
Object person = clazz.getDeclaredConstructor().newInstance();

Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 打破 private 限制
Object value = field.get(person);
System.out.println(value); // 输出 张三

四、完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
java复制编辑public class Person {
private String name;

public Person() {
this.name = "默认姓名";
}

public void sayHello(String msg) {
System.out.println(name + " 说:" + msg);
}
}
java复制编辑public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("Person");

Object obj = clazz.getDeclaredConstructor().newInstance();

Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "李四");

Method method = clazz.getMethod("sayHello", String.class);
method.invoke(obj, "你好,反射");
}
}

输出结果:

1
2
复制编辑
李四 说:你好,反射

五、反射的优缺点

优点

  • 灵活:允许在运行时操作对象
  • 解耦:可用于工厂模式、框架自动装配
  • 强大:能访问私有成员、动态调用

缺点

  • 性能较低:反射调用本质是方法分发 + 安全检查
  • 安全性弱:能访问和修改 private 属性可能导致安全问题
  • 可读性差:代码不直观,难以调试

六、反射在实际开发中的应用

应用场景 示例
框架自动注入 Spring IOC、DI
AOP 方法增强 Spring AOP
JDBC 封装 MyBatis 动态 SQL 映射
配置文件驱动类加载 SPI 插件机制
单元测试调用私有方法 JUnit、Mockito
序列化/反序列化 Jackson、FastJSON

七、Class 对象详解

每个 .class 文件在 JVM 中会被加载为唯一的 Class 实例对象,常见用法:

1
2
3
4
5
6
7
java复制编辑Class<?> clazz = MyClass.class;

System.out.println(clazz.getName()); // 全类名
System.out.println(clazz.getSimpleName()); // 简类名
System.out.println(clazz.getPackage()); // 包信息
System.out.println(clazz.getSuperclass()); // 父类
System.out.println(clazz.getInterfaces()); // 接口

八、注意事项

  • 反射可访问私有成员,但必须显式设置 setAccessible(true)
  • 建议避免在性能敏感场景频繁使用反射
  • Class.forName() 会触发类的初始化(执行静态代码块)
  • Java 9+ 中对反射访问做了封装限制(需打开模块)