@retention默认策略是retentionpolicy.class,注解写入.class文件但运行时不可见;source需显式声明,仅存于源码;runtime支持反射读取。

不是这样。没有声明 @Retention 的注解,默认保留策略是 RetentionPolicy.CLASS,不是 SOURCE。
默认值其实是 CLASS,不是 SOURCE
Java 规范明确规定:如果自定义注解未显式使用 @Retention,它的保留策略默认为 RetentionPolicy.CLASS。这意味着注解会写入 .class 文件,但 JVM 在运行时不会加载它,反射也读不到。
- 比如你写:
@interface MyAnno { String value() default ""; }——它等价于@Retention(RetentionPolicy.CLASS) -
RetentionPolicy.SOURCE只用于明确需要“编译即丢”的场景,如@Override,但它本身是由 JDK 预定义并显式标注了@Retention(SOURCE)的 - 没有任何内置或自定义注解在未加
@Retention时会自动变成 SOURCE
为什么有人误以为默认是 SOURCE?
常见误解来源有三个:
- 看到
@Override这类注解在运行时反射不到,就推断“没写 @Retention 就是 SOURCE”——其实它是显式声明为 SOURCE 的 - 混淆了“IDE 或编译器能识别”和“注解是否保留在字节码中”:SOURCE 注解只对 javac 和 IDE 有效,CLASS 注解对 javac 和字节码工具(如 ASM)有效,但对反射无效
- 某些旧资料或博客错误表述,把“不写 @Retention → 编译器不报错 → 像没用一样”等同于“只在源码存在”,忽略了它实际已进入 .class
怎么验证默认确实是 CLASS?
你可以用 javap 反编译验证:
- 定义一个无
@Retention的注解:@interface Loggable {} - 编译后执行:
javap -v Loggable.class | grep -A5 "RuntimeVisibleAnnotations" - 会看到类似
RuntimeVisibleAnnotations属性(说明注解进了 class 文件),但运行时调用getAnnotation(Loggable.class)仍返回 null ——这正是 CLASS 策略的行为
什么时候才真正是 SOURCE?
只有显式写成这样,才是真正的源码期注解:
@Retention(RetentionPolicy.SOURCE)<br>@interface CompileOnly { String value(); }
这种注解:
- 不会出现在 .class 文件里(javap 查不到)
- 编译完就彻底消失,连字节码工具都看不到
- 适合纯编译检查或 Lombok 类生成器——它们在编译阶段介入,不需要运行时存在











