Java 反射(Reflection)可以一句话概括为:在运行时"反过来"查看和操作类、方法、字段、构造器等元数据的能力。它是很多框架(Spring、MyBatis、Jackson)的底层基石。
下面用面试 + 实战角度帮你系统梳理。
一、反射能干什么?(核心能力)
能力 示例
运行时获取类信息 类名、修饰符、父类、接口
运行时创建对象 clazz.newInstance() / constructor.newInstance()
运行时调用方法 method.invoke(obj)
运行时读写字段 field.get(obj) / field.set(obj)
绕过访问权限 访问 private 成员
二、获取 Class 对象的三种方式(必会)
// 1. 类名.class(最常用,编译期已知)
Class<?> clazz1 = User.class;
// 2. 对象.getClass()
User user = new User();
Class<?> clazz2 = user.getClass();
// 3. Class.forName()(最灵活,框架最爱)
Class<?> clazz3 = Class.forName("com.example.User");
✅ 区别
• forName:会触发类加载 + 静态代码块
• .class:不会立即初始化
三、反射常用 API(重点)
1️⃣ 构造方法(Constructor)
Constructor ctor =
User.class.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true); // 突破 private
User user = ctor.newInstance("Tom", 18);
2️⃣ 字段(Field)
Field field = User.class.getDeclaredField("age");
field.setAccessible(true);
int age = (int) field.get(user);
field.set(user, 20);
3️⃣ 方法(Method)
Method method = User.class.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(user, "World");
四、反射 vs new(面试高频)
对比项 new 反射
编译期检查 ✅ 有 ❌ 无
性能 快 慢(有开销)
灵活性 低 极高
安全性 高 可被绕过
典型场景 普通业务 框架、插件
✅ 结论
• 业务代码:禁止滥用反射
• 框架代码:必须使用反射
五、反射在框架中的真实用途
Spring
• @Autowired:反射注入字段
• @ComponentScan:扫描包 → Class.forName
• AOP:反射 + 动态代理
MyBatis
• 反射读取实体字段 → SQL 映射
• 反射调用 setter / getter
Jackson
• JSON → Java 对象(反射创建 + 赋值)
六、反射的安全与性能问题(重点)
1️⃣ 安全问题
field.setAccessible(true); // 破坏封装
❗ 可能绕过安全检查,甚至修改 final 字段(JDK 9+ 受限)
2️⃣ 性能问题
• 方法调用比直接调用 慢 10~100 倍
• 解决方案:
• 缓存 Method / Field / Constructor
• 使用 sun.misc.Unsafe(极端场景)
• 使用 LambdaMetafactory(Spring 5+)
七、JDK 9 之后的变化(容易被忽略)
• 模块化(JPMS)
• 反射访问非导出包会被拒绝
• 需要 --add-opens
• setAccessible 受限
• 强封装模式下默认禁止
八、反射 + 注解(实战组合)
@Retention(RUNTIME)
@Target(FIELD)
@interface Column {
String value();
}
class User {
@Column("user_name")
private String name;
}
Field field = User.class.getDeclaredField("name");
Column column = field.getAnnotation(Column.class);
System.out.println(column.value()); // user_name
✅ 这是 ORM / 校验框架 的核心原理。
九、面试高频问题(可直接背)
✅ 反射是如何破坏单例的?
→ 通过私有构造器 + setAccessible(true)
✅ 反射为什么慢?
→ 方法查找、权限检查、参数装箱、JVM 优化困难
✅ 如何防止反射攻击单例?
→ 在构造器中判断实例是否已存在并抛异常
✅ 反射和动态代理的关系?
→ 动态代理底层依赖反射调用方法