要让自定义注解支持重复使用,必须定义符合三条件的容器注解并用@Repeatable声明:①为@interface;②含value()元素,类型为目标注解数组;③无非默认元素。

要让自定义注解支持重复使用(即在同一个元素上多次声明),必须定义一个“容器注解”(Container Annotation),并配合 @Repeatable 元素正确声明。否则编译器会报错:“Duplicate annotation”,且无法通过严格的注解处理检查(如 Java 8+ 的类型检查或 APT 工具)。
容器注解必须满足的三个硬性条件
容器注解不是任意写的,它需严格遵循以下规则:
-
必须是一个注解类型(用
@interface声明); -
必须声明一个名为
value的元素,其类型为「目标重复注解」的数组(例如MyAnno[] value() default {};); -
不能有其他非默认元素(即所有额外元素都必须提供默认值,否则编译失败;但最佳实践是只保留
value)。
重复注解与容器注解的配对写法
以自定义注解 @Role 为例,使其可重复使用:
@Repeatable(Roles.class)
public @interface Role {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Roles {
Role[] value() default {};
}
注意:@Repeatable 的参数必须是容器注解的 Class 对象(Roles.class),且容器注解本身必须有运行时保留策略(@Retention(RUNTIME))才能被反射读取。
编译器检查失败的常见原因
即使写了容器注解,仍可能因以下细节被编译器拒绝:
- 容器注解缺少
@Retention或@Target,导致元注解不完整; -
@Repeatable指向的容器类型与实际声明不一致(大小写、包名错误); - 容器中
value()的返回类型不是「目标注解」的数组(例如写成List<Role>或Role单个实例); - 目标重复注解未标注
@Repeatable,或标注了但容器不存在/不可见(如包私有、拼写错误)。
验证是否通过编译器严格检查的简单方法
写一个测试类,尝试在同一方法上重复使用该注解:
public class Test {
@Role("ADMIN")
@Role("USER")
void doSomething() {}
}
若编译通过,且 doSomething().getAnnotationsByType(Role.class) 返回长度为 2 的数组,则说明容器注解已正确通过编译器和运行时检查。

















