反射核心价值是运行时动态操作类结构,解决编译期类型不确定问题;常用于框架、序列化、测试;需避坑:缓存method/field、禁用循环反射、慎用setaccessible、适配jdk9+模块限制。

Java 反射不是背概念,而是讲清“为什么用”“怎么用”“用错会怎样”。面试官想看的,是你能不能在真实场景里判断该不该用反射、能不能避开典型坑。
反射的核心价值:运行时动态操作类结构
反射的本质,是让程序在运行时获取类的字节码信息(Class 对象),并动态调用方法、访问字段、创建实例。它不是为了炫技,而是解决编译期无法确定类型或行为的问题,比如框架(Spring、MyBatis)、序列化工具(Jackson)、单元测试(Mockito)都重度依赖它。
- Class.forName("com.example.User") 获取类对象,触发类加载和初始化
- clazz.getDeclaredMethod("setName", String.class) 获取私有方法(需 setAccessible(true))
- method.invoke(instance, "Alice") 绕过访问控制调用,但可能抛出 InvocationTargetException
高频陷阱题:反射性能差?那为什么 Spring 还大量用?
反射慢,主要慢在方法查找、权限检查、JVM 无法内联。但 Spring 并不是每次 getBean 都现场反射——它在启动时就缓存了 Method、Constructor、Field 对象,后续直接复用;还结合了 Unsafe(在特定版本)或字节码增强(如 CGLIB)做优化。真正要警惕的是在循环里反复调用 forName 或 getDeclaredMethod。
- 避免在热点路径(如 for 循环、高并发请求处理中)重复获取 Method/Field
- 用 Method.setAccessible(true) 减少权限校验开销(注意 JDK 9+ 模块系统限制)
- 考虑用 MethodHandle 或 VarHandle(JDK 9+)替代传统反射,性能更接近直接调用
必须能写出来的关键代码片段
面试常让你手写一段“通过反射给任意对象的私有字段赋值”,重点考察你对异常处理、访问控制、泛型擦除的理解:
public static void setPrivateField(Object target, String fieldName, Object value)
throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true); // 关键:跳过 private 检查
field.set(target, value);
}
补充点:如果字段是 static,set 时第一个参数传 null;如果类没 public 无参构造,newInstance() 会失败,得用 getDeclaredConstructor().newInstance()。
安全与兼容性:JDK 9+ 模块系统带来的变化
模块化后,默认模块间不能反射访问非 export 的包。比如想反射 java.util.ArrayList 的私有字段,JDK 9+ 会抛 InaccessibleObjectException。解决方案有二:
- 启动参数加 --add-opens java.base/java.util=ALL-UNNAMED(开发/测试可用,生产慎用)
- 优先使用官方 API(如 List 接口方法),而非硬反射内部字段——这是设计意图,不是 bug
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











