Java 反射机制(Reflection)
一、什么是反射
反射(Reflection) 是 Java 提供的一种机制,它允许程序在运行时动态获取类的信息(方法、属性、构造方法等)以及操作对象本身。
通过反射可以:
- 在运行时获取类的完整结构
- 动态创建对象
- 动态调用方法、访问字段
- 实现解耦、插件式开发、框架封装等
反射是实现诸如 Spring、MyBatis、Junit、Tomcat、IDEA 插件系统 的核心技术之一。
二、反射的核心类
反射主要在 java.lang.reflect
和 java.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, "你好,反射"); } }
|
输出结果:
五、反射的优缺点
优点
- 灵活:允许在运行时操作对象
- 解耦:可用于工厂模式、框架自动装配
- 强大:能访问私有成员、动态调用
缺点
- 性能较低:反射调用本质是方法分发 + 安全检查
- 安全性弱:能访问和修改 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+ 中对反射访问做了封装限制(需打开模块)