Java反射机制的核心是Class对象,它是JVM类加载时生成的唯一元数据镜像,所有反射操作均由此开始;setAccessible(true)并非绕过JVM访问控制,而是临时关闭Java语言层的安全检查,用于访问private成员。

Java反射机制的面试难点,不在“会不会用”,而在“为什么这么设计”和“哪里容易踩坑”。真正拉开差距的,是能不能讲清 Class 对象怎么来的、setAccessible 为什么能绕过访问控制、动态代理和反射的关系、以及性能与安全之间的权衡。
吃透 Class 对象:反射的唯一入口
所有反射操作都始于 Class 对象。它不是普通类的实例,而是 JVM 在类加载阶段为每个类生成的元数据镜像。关键点有三个:
- JVM 中每个类有且仅有一个 Class 对象,无论你用哪种方式获取,得到的都是同一个引用(可用 == 判断)
- Class.forName("xxx") 不仅加载类,还会触发静态代码块执行;而 XXX.class 只加载不初始化,适合需要延迟初始化的场景
- 泛型在运行时被擦除,所以 ArrayList<String>.class == ArrayList<Integer>.class,这也是反射无法直接获取泛型实际类型的原因
突破 private 的真实逻辑:setAccessible 不是“开后门”,而是关检查
很多人以为 setAccessible(true) 是 JVM 特许访问,其实它只是临时关闭 Java 语言层的安全检查(SecurityManager 检查),底层字段/方法仍受 JVM 访问规则约束。注意这些细节:
- 对 private 字段调用 setAccessible(true) 后,get() 和 set() 才不会抛 IllegalAccessException
- static final 基本类型常量(如 public static final int MAX = 100)可能被编译器内联,反射修改后,原变量值不变,但通过反射读取能拿到新值——这是面试高频陷阱题
- 调用 private 方法前必须 setAccessible(true),否则 invoke 会直接抛异常,不会静默失败
构造器与方法调用:别只记 API,要懂参数匹配逻辑
getMethod 和 getDeclaredMethod 的区别常被混淆。核心在于:
立即学习“Java免费学习笔记(深入)”;
- getMethod("xxx", A.class) 只查 public 方法,且会沿继承链向上查找(比如 Object 的 toString 也能被找到)
- getDeclaredMethod("xxx", A.class) 查当前类声明的所有方法(含 private),但不查父类
- 构造器同理:getConstructor() 只返回 public 构造器;getDeclaredConstructor() 才能拿到 private 构造器
- newInstance() 在 JDK 9+ 已废弃,必须用 Constructor#newInstance(),否则编译不通过
框架级应用反推原理:Spring 和 MyBatis 怎么用反射
面试官爱问“Spring Bean 是怎么创建的”,答案不能只说“用反射”,要拆解步骤:
- XML 或 @Bean 注解里配置的 class 全限定名 → Class.forName() 加载类
- 根据构造器参数类型匹配策略(如 byType / byName)→ getDeclaredConstructor() 获取构造器
- 若含 private 构造器或字段注入 → setAccessible(true) 后完成实例化和属性赋值
- MyBatis Mapper 接口没有实现类,靠 JDK 动态代理 + 反射 Method.invoke() 将接口方法转成 SQL 执行
不复杂但容易忽略


















