Repeating Annotations

在某些情况下,您希望对声明或类型使用应用相同的注解。从 Java SE 8 版本开始,重复 注解使您能够执行此操作。

例如,您正在编写代码以使用计时器服务,该服务使您可以在给定时间或特定时间表上运行方法,类似于 UNIX cron服务。现在,您要设置一个计时器,以在该月的最后一天以及每个星期五的晚上 11:00 运行一个方法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 编译器自动生成的“容器 注解”中。为了使编译器执行此操作,您的代码中需要两个声明。

步骤 1:声明可重复的 注解 类型

注解 类型必须标记为@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注解 中。

在未先声明可重复性的情况下将相同 注解 应用于声明会导致编译时错误。

步骤 2:声明包含 注解 的类型

包含 注解 的类型必须具有数组类型的value元素。数组类型的组件类型必须是可重复的 注解 类型。包含Schedules的 注解 类型的声明如下:

public @interface Schedules {
    Schedule[] value();
}

Retrieving Annotations

Reflection API 中有几种方法可用于检索注解。返回单个注解(例如AnnotatedElement.getAnnotation(Class<T>))的方法的行为不变,因为它们仅在存在所请求类型的* one *注解时才返回单个注解。如果存在多个所请求类型的 注解,则可以通过首先获取其容器 注解 来获取它们。这样,旧代码将 continue 起作用。 Java SE 8 中引入了其他方法,这些方法可扫描容器 注解 以一次返回多个 注解,例如AnnotatedElement.getAnnotationsByType(Class<T>)。有关所有可用方法的信息,请参见AnnotatedElement类规范。

Design Considerations

设计 注解 类型时,必须考虑该 注解 的“基数”。现在可以使用 注解 零次,一次,或者如果 注解 的类型标记为@Repeatable,则可以多次使用。也可以通过使用@Target元 注解 来限制可以在何处使用 注解 类型。例如,您可以创建一个只能在方法和字段上使用的可重复 注解 类型。认真设计 注解 类型非常重要,以确保程序员使用注解 会发现它尽可能灵活和强大。