getdeclaredfields()只返回当前类显式声明的字段(含private),不包含父类字段;需手动遍历getsuperclass()获取继承字段,getfields()则仅返回所有public字段(含父类)。

Java反射获取类名和字段时,getDeclaredFields() 为啥拿不到父类字段
因为 getDeclaredFields() 只返回当前类**显式声明**的字段(含 private),不向上查找继承链。想拿到父类字段,得手动遍历 getSuperclass(),一层层调用自己逻辑。
常见错误现象:NullPointerException 或字段列表为空,其实是误以为它能自动递归;或者用 getFields() 结果字段太少——它只返回 public 字段(含父类 public),但 private 和 package-private 的全丢了。
- 使用场景:写通用 DTO 转 Map 工具、序列化前扫描字段、低代码平台元数据提取
- 参数差异:
getDeclaredFields()返回所有声明字段;getFields()只返回 public 字段(含父类);getDeclaredField("name")查单个字段但会抛NoSuchFieldException - 性能影响:反射本身有开销,反复调用
getDeclaredFields()不建议在高频路径里;可缓存结果(比如用ConcurrentHashMap<class>, Field[]></class>)
用反射读取 private 字段值,必须调用 setAccessible(true) 吗
是的,JDK 12+ 默认开启强封装(--illegal-access=deny),不设 setAccessible(true) 会直接抛 IllegalAccessException。即使 JDK 8–11,不设也可能在模块化项目中失败。
容易踩的坑:只对字段对象调用了 setAccessible(true),但忘了在读取前检查是否已设(尤其多线程下字段对象复用);或者设了却没处理 SecurityException(极少见,但沙箱环境可能触发)。
- 实操建议:每次
get()前先field.setAccessible(true),别依赖“之前设过” - 兼容性注意:JDK 9+ 模块系统下,如果字段在非开放模块(如
java.base)里,仅setAccessible(true)不够,还需 JVM 启动参数--add-opens java.base/java.lang=ALL-UNNAMED - 替代思路:优先用 getter 方法(
getMethod("get" + ...)),比暴力破 private 更稳定
反射提取方法签名时,getGenericParameterTypes() 和 getParameterTypes() 有啥区别
getParameterTypes() 返回原始 Class 数组(擦除泛型后),比如 List<string></string> 变成 List.class;getGenericParameterTypes() 返回 Type 数组,能保留泛型信息(如 ParameterizedType),但要自己 cast 和解析。
典型错误:直接把 getGenericParameterTypes()[0] 当 Class 强转,结果 ClassCastException —— 它可能是 ParameterizedType、WildcardType 或 TypeVariable。
- 使用场景:写 JSON 反序列化器、RPC 接口参数校验、IDE 插件提示
- 实操建议:先用
instanceof ParameterizedType判断,再用getRawType()拿 Class,getActualTypeArguments()拿泛型实参 - 注意点:匿名内部类、lambda 表达式的方法无法通过反射可靠获取泛型信息;数组类型(
String[])在getGenericParameterTypes()中仍是Class,不是GenericArrayType
为什么用反射获取注解时,getAnnotation(Class<t>)</t> 返回 null,但 isAnnotationPresent() 是 true
因为注解的 @Retention 策略不是 RUNTIME。只有 @Retention(RetentionPolicy.RUNTIME) 的注解才能在运行时被反射读到;CLASS(默认)只保留在字节码,SOURCE 只在源码阶段存在。
常见混淆:以为 @Target 决定能否反射获取——其实 @Target 只控制能标在哪(类、方法等),真正决定“能不能拿到”的是 @Retention。
- 调试技巧:反编译 class 文件(
javap -v MyClass.class),搜索RuntimeVisibleAnnotations属性,没有就说明注解没保留到运行时 - 实操建议:自定义注解务必显式写上
@Retention(RetentionPolicy.RUNTIME) - 额外限制:如果注解本身用了泛型或嵌套注解,且未设
RetentionPolicy.RUNTIME,整个链路都会失效
反射看似简单,但每个 API 背后都卡着 JVM 规范、模块系统、泛型擦除三道关。最常被忽略的是:字段/方法的访问权限检查不是一次性开关,而是每次反射操作前都重新走一遍安全校验——所以 setAccessible(true) 必须紧挨着 get() 或 invoke() 写,中间穿插其他反射调用可能失效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











