@retention策略决定注解在字节码中是否存在及能否被反射读取:source编译后消失;class保留在字节码但不可反射;runtime既保留又支持反射,且默认策略为class。

Java注解的@Retention策略直接决定它在字节码中是否存在、以何种形式存在,以及能否被反射读取。仅看源码或IDE提示无法确认真实行为,必须通过字节码验证。
SOURCE策略:编译后彻底消失
该策略的注解只参与编译期检查,不会写入.class文件。javap反编译时完全搜不到相关痕迹。
- 执行
javap -v MyClass.class | grep Annotation,无任何输出 - 反射调用
getDeclaredAnnotations()返回空数组 - 典型例子:
@Override、@SuppressWarnings
CLASS策略:字节码可见但运行时不可反射
注解信息保留在class文件的RuntimeVisibleAnnotations或RuntimeInvisibleAnnotations属性中(实际JVM规范统一用前者,是否“可见”由RetentionPolicy语义决定),但JVM加载类时不将其暴露给反射API。
-
javap -v MyClass.class能查到注解签名,例如#12 = Utf8 Lcom/example/MyAnno;及对应属性表项 - 但
method.isAnnotationPresent(MyAnno.class)返回false - 适用于APT代码生成、ASM字节码增强等编译后处理场景
RUNTIME策略:字节码保留 + 反射可读
这是唯一支持运行时动态获取的策略。注解不仅写入字节码,还会被JVM加载进运行时元数据区。
-
javap -v中可见RuntimeVisibleAnnotations属性,且包含完整注解类型签名 -
getAnnotation(MyAnno.class)能正常返回实例 - 注意:默认保留策略是
CLASS,不显式声明RUNTIME就无法反射读取
验证方法要结合字节码与反射
单靠javap只能确认“是否写入”,不能替代运行时实测。正确做法是两步并行:
- 先用
javap -v TargetClass.class搜索RuntimeVisibleAnnotations和注解全限定名 - 再写测试代码,调用
getDeclaredAnnotations()或isAnnotationPresent()验证反射行为 - 两者都满足,才说明
@Retention(RetentionPolicy.RUNTIME)真正生效
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











