177. Java 注释 - 重复注释
从 Java SE 8
开始,Java
引入了 重复注释 (repeated annotations
)特性,这使得开发人员可以将相同的注释应用于同一个声明或类型使用的多个位置。这在一些场景下非常有用,特别是当需要在代码中对同一方法或类进行多次相同的注释时。
📌 示例场景:设置定时任务
假设正在编写一个应用程序,需要在每月的最后一天和每周五的晚上 11:00
执行清理任务。在没有重复注释的情况下,只能在方法上应用一次注释,但现在,通过重复注释,可以轻松为 doPeriodicCleanup()
方法添加多个定时执行的规则。
示例:使用重复注释设置定时任务
java
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "";
String dayOfWeek() default "";
String hour() default "";
}
java
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}
java
@Schedule(dayOfMonth="last") // 每月最后一天执行
@Schedule(dayOfWeek="Fri", hour="23") // 每周五晚上 11 点执行
public void doPeriodicCleanup() {
// 执行清理任务的代码
}
在上面的代码中,@Schedule
注解被应用于 doPeriodicCleanup()
方法两次,分别指定了两种不同的时间规则:一个是每月的最后一天,一个是每周五晚上 11 点。这种方式使得代码更清晰易懂,而不必创建多个定时器配置。
📌 示例场景:类级别的多重警报
再举一个例子,假设有一个处理未授权访问的异常类,需要分别为不同角色(如经理和管理员)发送警报。传统方法可能需要为每个角色配置不同的逻辑或注解,但通过重复注释,可以直接为同一个类应用多个注释。
示例:使用重复注释处理不同角色的警报
java
@Alert(role="Manager") // 针对经理的警报
@Alert(role="Administrator") // 针对管理员的警报
public class UnauthorizedAccessException extends SecurityException {
// 异常处理代码
}
在这个例子中,@Alert
注解被应用于 UnauthorizedAccessException
类两次,分别为不同角色的警报通知。这使得代码更加简洁且易于维护。
📌 步骤 1:声明可重复注释类型
要使用重复注释,首先需要声明注释类型是可重复的。这是通过使用 @Repeatable
元注解来实现的。@Repeatable
元注解的值是一个容器注解,容器注解是用来存储重复的注解的。
示例:声明可重复注释类型
java
import java.lang.annotation.Repeatable;
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
在这个例子中,@Schedule
注解被标注为 @Repeatable(Schedules.class)
,其中 Schedules
是用来存储重复 @Schedule
注解的容器注解。
📌 步骤 2:声明容器注释类型
接下来,需要声明一个容器注解类型,它的 value
元素是一个包含注释的数组。这个容器注解类型将作为存储多个重复注释的地方。
示例:声明容器注解
java
public @interface Schedules {
Schedule[] value();
}
在这个例子中,@Schedules
是一个容器注解类型,它包含一个 Schedule
类型的数组。每次应用多个 @Schedule
注解时,它们会被存储在 @Schedules
容器注解中。
📌 获取重复注释
Java
提供了多种方法来检索重复注释。使用反射 API
,可以通过以下方式获取容器注释,从而获取所有的重复注释。
- 获取单个注释 :
AnnotatedElement.getAnnotation(Class)
方法用于获取某个注释类型的第一个注释。 - 获取多个注释 :
AnnotatedElement.getAnnotationsByType(Class)
方法用于获取容器注释内的所有重复注释。
示例:使用反射获取重复注释
java
try {
// 获取当前类的Class对象
Class<?> myClass = Demo.class;
// 获取doPeriodicTask方法
Method method = myClass.getDeclaredMethod("doPeriodicTask");
// 获取Schedules注解
Schedules schedules = method.getAnnotation(Schedules.class);
if (schedules != null) {
for (Schedule schedule : schedules.value()) {
System.out.println("Day of Month: " + schedule.dayOfMonth());
}
}
// 也可以直接获取Schedule注解(如果只有一个)
Schedule[] scheduleArray = method.getAnnotationsByType(Schedule.class);
for (Schedule schedule : scheduleArray) {
System.out.println("Schedule - Day of Month: " + schedule.dayOfMonth() +
", Day of Week: " + schedule.dayOfWeek() +
", Hour: " + schedule.hour());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
在这个例子中,通过反射获取 @Schedules
容器注解,然后遍历其中存储的所有 @Schedule
注解,打印出每个注解的相关信息。
📌 设计注意事项
在设计可重复的注释时,有几个重要的注意事项:
- 注释的基数 :注释可以应用零次、一次或多次。如果注释类型被标记为
@Repeatable
,则可以多次使用该注释。 - 注释的适用位置 :通过
@Target
元注解,可以限制注释的应用位置。例如,可以创建只能用于方法和字段的可重复注释类型。 - 兼容性 :使用
@Repeatable
注解类型时,确保遵循 Java 的兼容性规则。由于@Repeatable
注解是容器注解,所以编译器会自动生成容器注解,并将多个相同的注释存储在容器中。
📌 总结
- 重复注释 :从
Java SE 8
开始,可以将相同的注释应用于同一声明或类型的多个位置。这通过使用@Repeatable
元注解实现。 - 应用场景:重复注释在需要为同一方法或类应用多个相同类型的注释时非常有用。例如,定时任务、角色警报等。
- 设计和使用 :设计可重复的注释时,考虑注释的应用基数以及注释类型的适用位置。使用
@Repeatable
元注解来定义可以重复应用的注释类型。
重复注释极大增强了 Java 代码的灵活性和可维护性,尤其是在处理多个类似的配置或规则时。