精准提取注解需确认其@retention(retentionpolicy.runtime)、通过class/method/field等annotatedelement调用getannotation(),注意私有成员需setaccessible(true),并判空处理属性值。

要精准提取类、方法或字段上的注解实例,关键不是调用 getAnnotation 就完事,而是明确目标注解类型、确认其保留策略(@Retention)、确保运行时可见,并正确选择被注解的元素进行反射访问。
确认注解的 RetentionPolicy 是 RUNTIME
只有声明为 @Retention(RetentionPolicy.RUNTIME) 的注解,才能在运行时通过反射获取。如果注解是 CLASS 或 SOURCE 级别,getAnnotation 会始终返回 null,且无任何异常提示。
- 检查你使用的注解源码,或文档,确认其保留策略
- 自定义注解时务必显式加上:@Retention(RetentionPolicy.RUNTIME)
- 例如 Spring 的
@Component、JUnit 的@Test都是 RUNTIME 级别
按目标元素类型调用对应反射 API
不能对任意对象调用 getAnnotation —— 它是 AnnotatedElement 接口的方法,而该接口由 Class、Method、Field、Constructor 等实现。必须先拿到具体元素实例:
-
类上注解:用
MyClass.class.getAnnotation(MyAnnotation.class) -
方法上注解:先获取
Method对象,如clazz.getDeclaredMethod("doSomething"),再调用method.getAnnotation(MyAnnotation.class) -
字段上注解:用
clazz.getDeclaredField("name"),再调用field.getAnnotation(MyAnnotation.class) - 注意:私有成员需先调用
setAccessible(true)才能访问(否则可能抛IllegalAccessException)
区分 getAnnotation 与 getDeclaredAnnotation(Java 8+)
两者行为不同,容易误用:
-
getAnnotation(Class<a>)</a>:只查当前元素**直接声明**的注解(不查继承来的),且对类而言,**不查父类/接口上的同名注解** -
getDeclaredAnnotation(Class<a>)</a>:语义更严格,也只查当前元素直接声明的注解;但对类来说,它**不会跨层级查找**,和getAnnotation在大多数场景下表现一致 - 真正影响“是否继承”的是注解自身的
@Inherited元注解 —— 仅对Class级注解生效,且只作用于子类(不适用于方法/字段) - 推荐优先使用
getAnnotation,语义清晰;除非明确需要排除间接声明(极少见),否则无需刻意换用getDeclaredAnnotation
安全提取并处理注解属性值
拿到注解实例后,通常需读取其属性。Java 注解属性本质是接口方法,调用即获得默认值或显式设置的值:
- 直接调用注解实例的方法,如
myAnn.value()、myAnn.order() - 若属性未显式指定,将返回定义时的
default值(注意:基本类型不能为null,但引用类型可为null) - 建议加空判断:
if (ann != null) { String v = ann.value(); ... },避免 NPE - 若需批量处理多个同类型注解(如
@MyAnn可重复),应改用getAnnotationsByType(需注解标注@Repeatable)










