@repeatable 解决了同一位置无法重复使用相同注解的痛点,使语义清晰、反射获取扁平化;需配合容器注解使用,且仅支持 runtime 保留策略。

Java 8 引入的 @Repeatable 解决了一个长期存在的痛点:以前同一个位置不能多次使用同一个注解,开发者只能被迫封装成容器注解,写法冗余且不直观。它的核心价值不是“多写几次”,而是让重复语义真正可表达、可读、可反射获取。
为什么需要 @Repeatable
在 Java 8 之前,若想为一个方法标记多个权限角色,只能这样写:
- 先定义单个注解:
@interface Role { String value(); } - 再定义“容器”注解:
@interface Roles { Role[] value(); } - 最后使用:
@Roles({@Role("ADMIN"), @Role("EDITOR")})
这种写法绕弯、易出错,且反射读取时需多层解包。@Repeatable 让你可以直接写成:@Role("ADMIN") @Role("EDITOR"),语义清晰,操作扁平。
@Repeatable 的正确用法
它不是独立使用的注解,而是一对协作结构:
- 被重复的注解(如
@Role)必须用@Repeatable(Roles.class)声明,括号里是其容器注解的类类型 - 容器注解(如
@Roles)必须声明一个value()成员,类型为该被重复注解的数组(Role[] value();) - 两个注解的
@Target和@Retention必须一致,否则编译报错
例如:@Repeatable(Constraints.class) 表示 @Constraint 可重复,而 @Constraints 就是它的合法容器。
运行时如何获取重复注解
反射 API 在 Java 8 中同步升级,提供两种方式:
-
getAnnotationsByType(Role.class)—— 直接返回所有@Role实例数组,最常用 -
getAnnotation(Roles.class)—— 获取容器注解本身,仅当显式写了容器形式时才非空
注意:getAnnotations() 仍只返回容器注解(如果存在),不会展开;所以业务代码应优先用 getAnnotationsByType。
常见误区与限制
@Repeatable 不是万能语法糖,有明确边界:
- 仅适用于
@Retention(RUNTIME)注解,因为只有运行时注解才涉及反射读取场景 - 不能用于
@Retention(SOURCE)或@Retention(CLASS)的注解 - 容器注解本身不能被
@Repeatable修饰,避免嵌套爆炸 - 若同时写了
@Role("A")和@Roles({@Role("B")}),反射调用getAnnotationsByType会合并返回 A 和 B
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











