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 优化困难

✅ 如何防止反射攻击单例?
→ 在构造器中判断实例是否已存在并抛异常

✅ 反射和动态代理的关系?
→ 动态代理底层依赖反射调用方法

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐