关键在于将@Retention设为RUNTIME:需显式声明@Retention(RetentionPolicy.RUNTIME)并配合@Target,避免默认CLASS策略;注解仅在运行时通过反射(如method.getAnnotation())获取,不参与编译或自动执行。

要编写只在运行时生效的自定义注解,关键在于将注解的 @Retention 策略设为 RetentionPolicy.RUNTIME,并确保不添加 @Target 以外的多余元注解(如 @Documented 或 @Inherited 非必需),同时避免使用 CLASS 或 SOURCE 级别。
1. 正确定义注解的保留策略
Java 注解默认保留策略是 RetentionPolicy.CLASS(编译后保留在 .class 中,但 JVM 不加载),若想在运行时通过反射读取,必须显式声明为 RUNTIME:
- 使用
@Retention(RetentionPolicy.RUNTIME) - 搭配
@Target指定可标注的位置(如类、方法、字段等) - 可选添加
@Documented(生成 Javadoc 时包含该注解)或@Repeatable(支持重复使用),但它们不影响“是否运行时可见”
2. 示例:一个仅运行时可用的方法级注解
下面是一个典型的安全检查注解,仅在运行时通过反射触发逻辑:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequireAdmin {
String value() default "admin";
}
这个注解不会影响编译或字节码结构,也不会被 javac 或 IDE 在编译期处理——只有在程序运行中调用 method.getAnnotation(RequireAdmin.class) 才能获取到它。
立即学习“Java免费学习笔记(深入)”;
3. 运行时读取注解的典型方式
在运行时检查注解需借助反射 API,且目标元素(类/方法/字段)必须已加载进 JVM:
- 对方法:用
Method#getAnnotation(Class)或getAnnotationsByType() - 对类:用
Class#getAnnotation(Class) - 注意:如果类未被加载(如未 new / 未被 ClassLoader 显式加载),反射无法访问其注解
- Spring AOP、JUnit5 等框架正是基于此机制实现切面或测试生命周期控制
4. 常见误区提醒
以下做法会导致注解“无法在运行时获取”:
- 漏写
@Retention(RetentionPolicy.RUNTIME)(默认是 CLASS,反射拿不到) - 误用
@Retention(RetentionPolicy.SOURCE)(仅保留在源码,编译后即丢弃) - 标注了注解但未在运行时主动调用反射 API 读取(注解本身不会自动触发任何行为)
- 在模块化环境(Java 9+)中,若模块未导出含注解的包,或未在
module-info.java中声明opens,反射可能被模块系统限制


















