# 重复注解

> 原文： [https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html](https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html)

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

例如，您正在编写代码以使用计时器服务，该服务使您能够在给定时间或某个计划上运行方法，类似于 UNIX `cron` 服务。现在你要设置一个计时器来运行一个方法， `doPeriodicCleanup` ，在每个月的最后一天和每个星期五晚上 11 点运行。要将计时器设置为运行，请创建`@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();
}

```

## 检索注解

Reflection API 中有几种可用于检索注解的方法。返回单个注解的方法（例如 [AnnotatedElement.getAnnotation（Class&lt; T&gt;）](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotation-java.lang.Class-)）的行为不变，因为如果 _ 一个 _ 注解，它们只返回单个注解。请求的类型存在。如果存在多个所请求类型的注解，则可以通过首先获取其容器注解来获取它们。通过这种方式，遗留代码继续工作。在 Java SE 8 中引入了其他方法，其扫描容器注解以一次返回多个注解，例如 [AnnotatedElement.getAnnotationsByType（Class&lt; T&gt;）](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotationsByType-java.lang.Class-)。有关所有可用方法的信息，请参阅 [AnnotatedElement](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html) 类规范。

## 设计注意事项

设计注解类型时，必须考虑该类型注解的 _ 基数 _。现在可以使用注解零次，一次，或者，如果注解的类型标记为`@Repeatable`，则不止一次。也可以通过使用`@Target`元注解来限制可以使用注解类型的位置。例如，您可以创建只能在方法和字段上使用的可重复注解类型。仔细设计注解类型非常重要，以确保程序员 _ 使用 _ 注解发现它尽可能灵活和强大。