必须通过getAnnotationsByType()获取重复注解,因@Repeatable在字节码中被编译为容器注解,getAnnotation()仅查“直接存在”的单个注解,而子注解属“间接存在”,故返回null或首个实例。

Java 中 @Repeatable 注解的“包装盒”(即容器注解)在运行时不会自动展开为子注解数组,JVM 只会查到容器注解本身。要拿到所有重复声明的子注解实例,**必须通过反射调用 getAnnotationsByType() 方法**,而不是 getAnnotation() 或 getAnnotations()。
为什么 getAnnotation() 拿不到重复注解?
getAnnotation(Class<T>) 设计上只返回单个注解实例(或 null),它不处理可重复场景;即使你写了多个 @MyAnno,它也只会返回第一个(或随机一个),甚至可能返回 null —— 因为 JVM 实际存储的是容器注解,原始子注解在字节码中被“打包”进容器里了。
正确方式:用 getAnnotationsByType()
这是 Java 8 引入的专用方法,专为 @Repeatable 场景设计。它会自动识别容器注解,并把里面所有子注解实例提取出来,组成数组返回:
- 对类、方法、字段等元素调用
element.getAnnotationsByType(MyAnno.class) - 返回的是
MyAnno[],长度等于你实际声明的次数 - 无需手动解析容器注解,JVM 和反射 API 已内置支持
容器注解不是“摆设”,但一般不用手动读
容器注解(如 @MyAnnoContainer)确实存在于运行时,可通过 getAnnotation(MyAnnoContainer.class) 获取。它通常有一个 value() 方法返回子注解数组。但除非你要做特殊元编程(比如校验容器是否被手写、绕过 @Repeatable 规则),否则没必要走这条路 —— getAnnotationsByType() 更安全、语义更清晰、兼容性更好。
注意边界情况
该方法仅在目标元素(类/方法/字段)上**直接声明**了重复注解时才有效。如果注解是通过类型注解(@Target(TYPE_USE))加在泛型、数组维度等位置,或嵌套在其他注解里(即“元注解链”),getAnnotationsByType() 默认不递归查找。此时需结合 getDeclaredAnnotations() + 手动遍历 + 容器解包逻辑,但属于高级用法,日常开发极少遇到。

















