该Java教程针对JDK 8编写。本页面中描述的示例和实践不利用后续版本引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改,了解Java SE 9及以后版本中的更新语言特性摘要。
请参阅JDK发行说明,了解所有JDK版本的新功能、增强功能以及已删除或不推荐使用的选项的信息。
有一些情况下,您希望将相同的注解应用于声明或类型使用。从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编译器自动生成的容器注解中。为了让编译器这样做,您的代码中需要两个声明。
该注解类型必须用@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(); }
Reflection API中有几种可用的方法用于检索注解。返回单个注解的方法的行为,如AnnotatedElement.getAnnotation(Class<T>),在只有一个请求的类型的注解存在时返回一个注解,其行为不变。如果存在多个请求类型的注解,可以通过首先获取它们的容器注解来获取它们。这样,旧代码可以继续使用。Java SE 8中引入了其他方法,可以通过扫描容器注解一次性返回多个注解,如AnnotatedElement.getAnnotationsByType(Class<T>)。有关所有可用方法的信息,请参见AnnotatedElement类规范。
在设计注解类型时,必须考虑该类型的注解的基数。现在可以使用注解零次、一次,或者如果注解类型被标记为@Repeatable
,则可以使用多次。还可以使用@Target
元注解来限制注解类型的使用位置。例如,可以创建一个可重复使用的注解类型,只能用于方法和字段上。设计注解类型时要仔细考虑,以确保程序员在使用注解时能够发现它具有尽可能灵活和强大的功能。