只有@retention(retentionpolicy.runtime)的注解能被反射读取,因其信息写入class文件的runtimevisibleannotations属性并在类加载时进入jvm元空间;source策略编译后消失,class策略虽存于class文件但不加载进运行时内存。

Java反射只能读取 @Retention(RetentionPolicy.RUNTIME) 的注解,其他策略(SOURCE、CLASS)在运行时不可见。
为什么只有 RUNTIME 能被反射读取
RUNTIME 策略让注解信息写入 class 文件的 RuntimeVisibleAnnotations 属性,并在类加载时进入 JVM 元空间,反射 API 才能访问。其余两种策略不具备这个能力:
- SOURCE:只保留在源码中,编译后就消失,class 文件里完全找不到
-
CLASS:写入 class 文件(可见于
javap -v中的RuntimeInvisibleAnnotations),但 JVM 不加载进运行时内存,getAnnotation()永远返回null
如何确认注解是否支持反射读取
不能只看代码有没有加 @Retention,要两步验证:
- 用
javap -v YourClass.class搜索RuntimeVisibleAnnotations和你的注解全限定名(如Lcom/example/MyAnno;) - 写测试代码调用
method.getAnnotation(MyAnno.class)或clazz.isAnnotationPresent(MyAnno.class),检查是否返回非 null 实例
反射读取 RUNTIME 注解的正确姿势
即使策略正确,操作不当也会拿不到注解:
- 类、方法、字段需分别调用对应对象的
getAnnotation(YourAnno.class) - 私有成员(private method/field)必须先调用
setAccessible(true) - 父类声明的注解不会自动出现在子类重写的方法上;
@Inherited只对ElementType.TYPE(类)生效,对方法无效 - 确保运行时 ClassLoader 能加载到注解类本身(避免模块隔离或双亲委派导致类不可见)
常见失效原因和排查要点
如果 getAnnotation() 返回 null,优先检查:
- 注解定义里是否漏写了
@Retention(RetentionPolicy.RUNTIME) - 目标元素(比如某个 method)是否真的被该注解标记(注意包路径、拼写、是否误加在参数或局部变量上)
- 是否在 AOP 代理生成前、字节码增强未完成时就尝试读取(例如 Spring 早期初始化阶段)
- 反射获取的是 declared 方法/字段,若想跨继承链查找,需手动向上遍历父类或接口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











