反射读取自定义注解必须设置@retention(retentionpolicy.runtime),否则getannotation()返回null;默认class策略使注解仅存于字节码,反射不可见;source在编译后丢弃,runtime才支持运行时反射获取。

想用反射读取自定义注解,@Retention 必须设为 RUNTIME。否则 getAnnotation() 总是返回 null,而且不报错、不警告——这是最常踩的坑。
为什么反射拿不到注解?
根本原因在于注解没“活到运行时”。Java 默认用 CLASS 策略,注解写进 .class 文件,但 JVM 加载类时不把它放进内存,反射自然看不见。
- 没写 @Retention → 默认 RetentionPolicy.CLASS → 反射不可见
- @Retention(SOURCE) → 编译完就丢 → .class 里根本没有
- @Retention(RUNTIME) → 注解随类一起加载 → 可通过 Method.getAnnotation()、Class.isAnnotationPresent() 等调用获取
三种策略对应的实际效果
每种 RetentionPolicy 决定了注解在哪个环节还能被谁访问:
- SOURCE:只给编译器用,比如 @Override。javac 检查完就扔,.class 文件里搜不到
- CLASS:保留在字节码中,ASM、Javassist 这类字节码工具能读,但反射 API 拿不到
- RUNTIME:唯一能让反射读取的选项。Spring 的 @Autowired、JUnit 的 @Test、自定义 AOP 注解都靠它
怎么验证注解是否生效?
别猜,直接看字节码:
- 运行
javap -v YourClass.class - 搜索
RuntimeVisibleAnnotations→ 说明用了 RUNTIME - 搜到
RuntimeInvisibleAnnotations→ 对应 CLASS 策略 - 什么都没搜到 → 很可能是 SOURCE 或根本没加注解
搭配 @Target 才算完整
@Retention 控制“活多久”,@Target 控制“能标在哪”。光有 RUNTIME 不够,还得明确标注位置,否则可能误用:
- 标在方法上却忘了声明 @Target(ElementType.METHOD)
- IDE 不提示、编译也不报错,但运行时扫描逻辑可能漏掉或出错
- 推荐写全:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD})
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











