在一些场景中你想要在声明或者类型使用上添加一些相关的注解。Java SE 8 release
中提供了repeating annotations
实现这个功能。
例如,你想使用定时服务编写代码使得在指定时间或者是按特定计划运行一个函数,类似于UNIX
中的cron
服务。现在你想设置一个定时器去运行函数doPeriodicCleanup
,该定时器在每个月的最后一天和每个星期五晚上11点整启动。为了实现定时器,创建一个名为@Schedule
的注解,并在doPeriodicCleanup
函数上使用两次。第一次我们指定每个月的最后一天,第二次我们指定星期五晚上11点整,具体代码如下所示:
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
这个例子在函数上应用注解。你可以使用标准注解的所有地方重复注解。例如,你有一个处理未授权访异常的类,。你在类上为manager
和其他admin
添加一个@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编译器用来生成并保存重复注解的container annotation
(容器注解)的类型。这个例子中,容器注解的类型是Schedules
,也就是说重复的@Schedule
注解保存在一个@Schedules
注解中。
将相同的未声明可重复的注解应用在同一个声明中会导致编译时报错。
容器注解类型必须包含一个数组类型的value
元素。数组中元素的类型必须是可重复注解类型。名为Schedules
的容器注解声明如下:
public @interface Schedules {
Schedule[] value();
}
Retrieving Annotations
Reflection API
提供了一些函数用来获取注解。有些函数返回单个注解,比如 AnnotatedElement.getAnnotation(Class),如果存在所请求类型的一个注释,它们仅返回单个注释,如果存在一个以上的注解,你可以先通过使用它们的容器注解来获取它们。通过这样,确保遗产代码能正常运行。Java SE 8中的其他函数可以扫描容器注解使得一次放回多个注解,比如AnnotatedElement.getAnnotationsByType(Class)。阅读AnnotatedElement的规范获取跟多信息。
Design Considerations
当设计一个注解类型时,你必须考虑该类型的注解cardinality
(基数)。现在可以不使用注解或者使用一次,如果注解的类型被标记为@Repeatable
可以使用多次。可以通过使用@Target
来限制使用一个注解的地点。例如你可以创建一个只能用在函数和属性上的可重复注解。认真的设计你的注解类型是很重要的,这样可以确保开发在使用发现它既灵活有强大