Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
在某些情况下,你希望将相同的注解应用于声明或类型用途。从 Java SE 8 发行版开始,repeating annotations (重复注解) 使你能够执行此操作。
例如,你正在编写代码以使用计时器服务,该服务使你能够在给定时间或某个计划上运行方法,类似于 UNIX cron 服务。现在,你要设置计时器以在该月的最后一天以及每周五的晚上 11 点运行方法 doPeriodicCleanup。要将计时器设置为运行,请创建 @Schedule
注解并将其应用于 doPeriodicCleanup 方法两次。第一次使用指定月份的最后一天,第二次使用指定星期五晚上 11 点,如下面的代码示例所示:
@Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup() { ... }
前面的示例将注解应用于方法。你可以在使用标准注解的任何位置重复注解。例如,你有一个用于处理未授权访问异常的类。你使用一个 @Alert
注解为管理员和其他管理者注解该类:
@Alert(role="Manager") @Alert(role="Administrator") public class UnauthorizedAccessException extends SecurityException { ... }
出于兼容性原因,重复注解存储在由 Java 编译器自动生成的 container annotation (容器注解) 中。为了使编译器执行此操作,代码中需要两个声明。
注解类型必须使用 @Repeatable
元注解进行标记。以下示例定义自定义 @Schedule
可重复注解类型:
import java.lang.annotation.Repeatable; @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; }
括号中的 @Repeatable
元注解的值是 Java 编译器为存储重复注解而生成的容器注解的类型。在此示例中,包含注解类型为 Schedules
,因此重复 @Schedule
注解存储在 @Schedules
注解中。
将相同的注解应用于声明而不首先声明它是可重复的,这会导致编译时错误。
容器注解类型必须具有带有数组类型的 value
元素。数组类型的组件类型必须是可重复的注解类型。容器注解类型的 Schedules
的声明如下:
public @interface Schedules { Schedule[] value(); }
反射 API 中有几种可用于获取注解的方法。返回单个注解的方法(例如 AnnotatedElement.getAnnotation(Class<T>))的行为未更改,如果请求的类型只存在 一个 注解,则只返回单个注解。如果存在多个所请求类型的注解,则可以通过首先获取其容器注解来获取它们。通过这种方式,遗留代码继续工作。Java SE 8 中引入了其他方法,它们扫描容器注解以一次返回多个注解,例如 AnnotatedElement.getAnnotationsByType(Class<T>)。有关所有可用方法的信息,请参阅 AnnotatedElement 类规范。
设计注解类型时,必须考虑该类型注解的 cardinality (基数)。现在可以使用注解零次,一次,或者,如果注解的类型标记为 @Repeatable
,则不止一次。也可以通过使用 @Target
元注解来限制可以使用注解类型的位置。例如,你可以创建只能在方法和字段上使用的可重复注解类型。仔细设计注解类型非常重要,以确保程序员 使用 注解发现它尽可能灵活和强大。