学java反射的核心是理解“运行时动态操作类”,关键在于掌握class对象获取、成员操作及避坑要点:class是入口,唯一且分三种获取方式;field/method需区分getdeclaredxxx与getxxx,私有成员须setaccessible(true);典型场景包括动态执行、打印字段、调用private构造器、获取泛型类型;需注意性能损耗、模块限制与安全风险。

学Java反射,关键不是背API,而是理解“运行时动态操作类”这个核心逻辑。掌握它不需要死记硬背,重点是搞清三件事:怎么拿到类的描述信息、怎么用这些信息创建对象或调用方法、哪些地方容易踩坑。
先搞懂 Class 对象才是反射的真正入口
所有反射操作都从 Class 对象开始,它不是普通对象,而是 JVM 在类加载时生成的元数据容器。一个类无论 new 多少次,它的 Class 对象始终唯一。
- 类名.class:编译期已知类,最安全高效,不触发类初始化
- 对象.getClass():已有实例时用,适合类型不确定的场景
- Class.forName("全限定名"):运行时动态加载,框架最常用,会触发类的初始化
用 Field 和 Method 拿到并操作成员
拿到 Class 后,就能获取字段(Field)、方法(Method)、构造器(Constructor)等结构信息。注意区分 getDeclaredXXX 和 getXXX:
- getDeclaredXXX:能拿到本类声明的所有成员,包括 private 的
- getXXX:只返回 public 成员,且包含父类继承来的 public 成员
- 访问私有成员前必须调用 setAccessible(true),否则抛 IllegalAccessException
- 调用 method.invoke(obj, args) 时,静态方法传 null 作第一个参数;field.get(obj) 同理
动手写几个典型小例子练手感
别一上来就啃框架源码,先用真实小场景验证理解:
- 读取配置文件里的类名和方法名,用反射执行——模拟 Spring 的 Bean 初始化
- 给任意对象打印所有字段名和值(含 private 字段)——类似通用 toString 工具
- 绕过构造器限制,用反射调用 private 构造器创建单例对象——理解反序列化或测试场景
- 通过反射获取泛型实际类型(如 List
中的 String)——解决 JSON 反序列化类型擦除问题
注意性能和安全性边界
反射不是万能钥匙,用对地方才叫能力,乱用就是隐患:
- 反射调用比直接调用慢很多,频繁使用要考虑缓存 Method 或 Constructor 实例
- JDK 9+ 引入模块系统,跨模块访问需在 module-info.java 中显式 opens 包
- setAccessible(true) 在安全管理器启用时可能被拒绝,生产环境需评估风险
- 避免在热路径(如循环内、高频接口)中反复通过 forName 加载类,易引发类加载瓶颈
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











