java反射核心在于打通“类加载→class对象→元数据操作”主线,class对象是唯一入口,具有唯一性;通过三种方式获取后,可借助field、method、constructor等api动态操作私有成员,setaccessible用于临时绕过访问检查。

Java 反射核心突破,关键不在“背API”,而在打通“类加载→Class对象→元数据操作”这条主线。掌握它,才能真正用好Spring、MyBatis这些框架的底层逻辑。
吃透 Class 对象:反射唯一的入口
所有反射操作都始于一个 Class 对象——它不是普通实例,而是 JVM 加载类后在元空间中生成的“类的镜像”。同一个类,无论 new 多少次,它的 Class 对象始终唯一(可用 == 判断)。
获取方式有三种,适用场景不同:
- 类名.class:编译期已知类型,安全高效,推荐用于工具类或配置固定场景
- 对象.getClass():已有实例但类型不确定(比如 Object 参数),适合泛型擦除后的类型还原
- Class.forName("全限定名"):运行时动态加载(如从配置文件、数据库读取类名),框架最常用,会触发类初始化
拆解类结构:字段、方法、构造器怎么拿
拿到 Class 后,就能“扫描”它的全部成员:
- 字段(Field):getDeclaredFields() 获取所有声明字段(含 private),配合 setAccessible(true) 可读写私有属性
- 方法(Method):getDeclaredMethod("methodName", paramTypes...) 精准定位方法,invoke(obj, args...) 动态调用
- 构造器(Constructor):getDeclaredConstructor(paramTypes...) 获取任意构造器,包括 private,再 setAccessible(true) + newInstance(...) 实例化
注意:getFields() 和 getMethods() 只返回 public 成员(含父类继承的),而 getDeclaredXXX 系列只返回本类声明的成员(含 private),不跨继承链。
绕过访问限制:setAccessible 的真实作用
它不是“取消权限检查”,而是临时关闭 Java 的访问控制校验。本质是告诉 JVM:“我知道风险,这次请放行”。
常见误区:
- 对 final 字段设值:能成功赋值,但若该字段是编译期常量(如 static final String),JVM 可能已内联,修改不影响后续读取
- JDK 9+ 模块系统下:需在 module-info.java 中显式开放包(opens 或 exports),否则 setAccessible 可能失败
实战中真正卡点的地方
反射本身不难,难在和实际场景结合时的细节处理:
- 泛型擦除后取真实类型:用 Method.getGenericReturnType() + TypeVariable 解析,不能只靠 getReturnType()
- 调用带 varargs 的方法:传参时要么展开数组,要么显式传 Object[],否则可能匹配到错误重载
- 异常处理:invoke() 抛出的是 InvocationTargetException,需用 getCause() 提取原始异常
- 性能敏感场景:缓存 Constructor/Method 对象,避免重复查找;高频调用可考虑用 MethodHandle 或 VarHandle 替代
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











