Java反射核心是在运行时动态操作未知类名、方法名、字段名的对象,适用于框架Bean装配、JSON序列化、私有字段测试等场景,需谨慎处理权限、类型兼容性、异常及JDK版本限制。

Java 反射不是靠“背API”就能掌握的,关键在于理解它在什么场景下必须用、为什么不能乱用,以及怎么避开那些一写就出错的坑。
反射的核心目的很朴素:在运行时,当类名、方法名、字段名都还不确定时,仍能操作对象。
比如框架要自动装配 Bean、JSON 库要序列化任意对象、测试工具要访问私有字段做断言——这些都不是编译期能写死的逻辑,必须靠反射动态完成。
一、看教程前先厘清三个前提
- 不是所有“动态”都需要反射。比如用
if-else或switch判断类型再调用,比反射更安全、更快。 - 反射破坏封装性(如强行访问
private字段)、绕过编译检查、性能开销明显,用之前得有正当理由。 - 真正的难点不在“怎么调用
getDeclaredField()”,而在“调用后要不要设setAccessible(true)”、“会不会触发 SecurityManager 拒绝”、“字段值类型和实际 get() 出来的类型是否匹配”。
二、重点看教程里是否讲清了这四类实操边界
-
获取字段时,
getDeclaredXXX和getXXX的区别必须列清楚-
getDeclaredField("x"):只找本类声明的字段,不管 public/private,但不继承父类字段; -
getField("x"):只找 public 字段,且会沿继承链向上找(包括父类的 public 字段); - 想读
ArrayList的elementData?只能用getDeclaredField,且必须setAccessible(true)。
-
-
调用方法或设置字段前,类型兼容性要手动兜底
Java注释规范Skills下载当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
Field f = obj.getClass().getDeclaredField("value"); f.setAccessible(true); Object raw = f.get(obj); // 返回的是 Object,不是 String! if (raw instanceof String) { System.out.println(((String) raw).length()); } -
构造对象时,别再用已废弃的
clazz.newInstance()
正确写法是获取Constructor后显式调用:Constructor> ctor = clazz.getDeclaredConstructor(String.class); ctor.setAccessible(true); Object instance = ctor.newInstance("hello"); -
异常处理不能只 catch
Exception
反射抛出的典型异常有三类:-
NoSuchFieldException/NoSuchMethodException→ 类结构不符,应提前校验; -
IllegalAccessException→ 权限不足,需配合setAccessible(true); -
InvocationTargetException→ 实际方法执行中抛出的异常,要用getCause()提取原始异常。
-
三、警惕教程里没明说但极易踩的坑
-
setAccessible(true)在 JDK 12+ 默认受限,尤其模块化项目中可能被SecurityManager或RuntimePermission拦截; -
getFields()返回的 public 字段数组,不包含static final常量(它们被内联优化,运行时已不存在); - 对泛型字段(如
List<string></string>)用反射读值,Field.getGenericType()才能拿到真实类型,getType()只返回List.class; - 多线程环境下反复调用
getDeclaredMethods()会产生新数组,建议缓存结果。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










