Java反射的核心是将Class对象作为运行时“类探针”,通过三步闭环掌握:稳抓三种Class获取方式的差异(.class不初始化、getClass()支持多态、forName()触发初始化);练熟对私有字段/方法/构造器的声明式操作(setAccessible+getDeclaredXXX);在Spring IOC、MyBatis映射、JSON反序列化等真实场景中还原反射逻辑,并注意缓存Method/Field、JDK9+模块限制及final字段优化陷阱。

想真正提升 Java 反射能力,不能只背 API,得从“理解动态性”出发,把反射当成运行时的“类探针”来用。核心是三步:稳抓 Class 入口、练熟字段/方法/构造器操作、在真实场景中闭环验证。
吃透 Class 对象的获取逻辑和差异
Class 是反射唯一入口,但三种获取方式行为不同,容易踩坑:
- 类名.class:编译期绑定,不触发类初始化(如静态块、static 字段赋值),适合工具类或配置类场景
- 对象.getClass():必须已有实例,返回的是该实例实际运行时类型(支持多态,比如子类对象调用会返回子类 Class)
- Class.forName("全限定名"):会触发类的初始化(执行 static 块),框架加载配置类、插件类时最常用;注意包名拼错或类路径缺失会抛 ClassNotFoundException
动手拆解一个类的完整结构
别停留在“能调用 public 方法”层面。拿一个含私有字段、私有方法、带参数构造器的实体类(如 User),逐项练习:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 getDeclaredFields() 获取所有字段(含 private),遍历并打印名称、类型、修饰符
- 对某个 private 字段调用 setAccessible(true),再用 field.set(obj, value) 修改值
- 用 getDeclaredMethod("methodName", paramTypes) 获取私有方法,设为可访问后 invoke(obj, args) 调用
- 用 getDeclaredConstructor(paramTypes) 获取私有构造器,设为可访问后 newInstance(args) 创建对象
在典型框架场景中还原反射逻辑
脱离框架谈反射是空谈。选一个你常用的场景反向推演:
立即学习“Java免费学习笔记(深入)”;
- Spring Bean 初始化:IOC 容器拿到 class 后,如何通过反射获取 @Autowired 字段、调用 setter 或构造器注入?试着手写简易版依赖注入流程
- MyBatis 结果映射:ResultSet 每行数据怎么映射到 User 对象?反射如何根据列名匹配字段(忽略大小写、下划线转驼峰)、跳过 final 字段、处理 null 值
- JSON 反序列化:Gson/Fastjson 怎么把 JSON 字符串转成对象?它用 getDeclaredFields() 还是 getFields()?private 字段是否默认支持?
关注性能与安全的实际约束
反射不是万能钥匙,用错反而拖垮系统:
- 频繁反射调用比直接调用慢 5–10 倍以上,关键路径(如高频循环)应缓存 Method/Field 对象,避免重复查找
- JDK 9+ 模块系统限制了对非开放模块内 private 成员的 setAccessible(true),需在 module-info.java 中声明 opens 或使用 --add-opens 启动参数
- 修改 final 字段可能无效——如果该字段被编译器优化为编译期常量(如 static final String = "abc"),反射改的是内存值,但代码里仍用内联常量

















