参考:
https://blog.csdn.net/sun_promise/article/details/51315032
https://docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html
https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
在JDK8之前,类型注解只能用在类型声明的地方:
@MyAnnotation // 声明类
public class Test {
}
JDK8后,类型注解可以在任何有类型的地方加入注解(包含泛型):
@MyAnnotation
public class Test<@MyAnnotation T> extends @MyAnnotation Fathers implements @MyAnnotation Callable {
private @MyAnnotation String name = "lisi";
public @MyAnnotation String test(@MyAnnotation String name) throws @MyAnnotation Exception {
@MyAnnotation String s = "test";
@MyAnnotation List<String> list = new @MyAnnotation ArrayList<>();
Number a = 1;
Integer i = (@MyAnnotation Integer) a;
if (list.get(0) == null) {
throw new @MyAnnotation Exception();
}
list.add(s);
return list.get(0);
}
@Override
public Object call() throws Exception {
return null;
}
}
在8种新增类型注释主要是为了改进Java的程序分析,配合类型检查框架做强类型检查,从而在编译期间确认运行时异常,比如 NullpointException,从而提高代码质量。
比如:
@NonNull Object my = null;
第三方工具会在编译期间自动检测my是否为null,如果为null,抛出异常或者警告
目前具有此项功能的检测框架有 The Check Framework
JDK8 新增ElementType.TYPE_USE
用来创建类型注解:
@Target({TYPE_USE})
@Retention(RUNTIME)
public @interface MyAnnotation {
}
注意:JDK8还提供了 TYPE_PARAMETER 类型的注解,表示可以修饰类型参数(泛型)的注解。
在8之前,一个目标只可以打一个注解:
@Test
private String name;
现在JDK8提供了Repeating Annotations,可以在一个目标上打上多个可重复注解:
@Test("a")
@Test("b")
private String name;
JDK8中提供了一个新的源注解,用于表示可重复注解:
// 创建可重复注解:指定容器类型为 Sechedules.class
@Repeatable(Schedules.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
// 可重复注解的容器注解,用于存放多个可重复注解:
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}
注意:如果想要在运行时获取注解,注解Retention
必须为RetentionPolicy.RUNTIME
,并且,Schedules与Schedule 注解的保留时期必须都为运行时!
获取可重复注解的方式同获取普通注解没有什么太大的区别:
@Schedule(hour = 9)
@Schedule(hour = 10)
public class Task {
public static void main(String[] args) throws Exception {
Schedule[] ats = Task.class.getAnnotationsByType(Schedule.class);
System.out.println(Arrays.toString(ats));
// [@test.s.Schedule(hour=9, dayOfMonth=first, dayOfWeek=Mon), @test.s.Schedule(hour=10, dayOfMonth=first, dayOfWeek=Mon)]
System.out.println(Arrays.toString(Task.class.getAnnotations()));
// [@test.s.Schedules(value=[@test.s.Schedule(hour=9, dayOfMonth=first, dayOfWeek=Mon), @test.s.Schedule(hour=10, dayOfMonth=first, dayOfWeek=Mon)])]
//注意:这里获取到的是 Schedules 注解,而不是多个 Schedule 注解
}
}
使用一个注解来存储重复的注解,编译后的class为:
@Schedules({@Schedule(hour = 9), @Schedule(hour = 10)})
public class Task {
public Task() {
}
public static void main(String[] args) throws Exception {
Schedule[] ats = (Schedule[])Task.class.getAnnotationsByType(Schedule.class);
System.out.println(Arrays.toString(ats));
System.out.println(Arrays.toString(Task.class.getAnnotations()));
}
}
所谓的可重复注解,只是编译层面的改动。