Java注解之Repeatable解读
作者:蜡笔没了小新git
Java注解之Repeatable
Repeatable使用场景
在需要对同一种注解多次使用时,往往需要借助@Repeatable。
实例
在生活中一个人往往是具有多种身份,如果我把每种身份当成一种注解该如何使用???
先声明一个Persons类用来包含所有的身份
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Persons { Person[] value(); }
这里@Target是声明Persons注解的作用范围,参数ElementType.Type代表可以给一个类型进行注解,比如类,接口,枚举,注解。
@Retention是注解的有效时间,RetentionPolicy.RUNTIME是指程序运行的时候。
Person注解:
@Repeatable(Persons.class) public @interface Person{ String role() default ""; }
@Repeatable括号内的就相当于用来保存该注解内容的容器。
声明一个Man类,给该类加上一些身份。
@Person(role="CEO") @Person(role="husband") @Person(role="father") @Person(role="son") public class Man { String name=""; }
在主方法中访问该注解。
public static void main(String[] args) { Annotation[] annotations = Man.class.getAnnotations(); System.out.println(annotations.length); Persons p1=(Persons) annotations[0]; for(Person t:p1.value()){ System.out.println(t.role()); } }
下面的代码结果输出相同,但是可以先判断是否是相应的注解,比较严谨。
if(Man.class.isAnnotationPresent(Persons.class)) { Persons p2=Man.class.getAnnotation(Persons.class); for(Person t:p2.value()){ System.out.println(t.role()); } }
运行结果:
1
CEO
husband
father
son
对@Repeatable的理解
@Repeatable
是jdk8中新增的注解,使用如Spring中的@ComponentScan
注解。
在没有@Repeatable
注解的的注解中,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解。
其官方文档如下:
The annotation type {@code java.lang.annotation.Repeatable} is used to indicate that the annotation type whose declaration it (meta-)annotates is repeatable.
The value of @Repeatable indicates the containing annotation type for the repeatable annotation type.
@Repeatable 注解是用于声明其它类型注解的元注解,来表示这个声明的注解是可重复的。
@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
示例
Value注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String value() default "value"; }
Values注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
其中,@Value
注解上的元注解@Repeatable
中的值,使用了@Values
注解,@Values
注解中包含的值类型是一个@Value
注解的数组!
这就解释了官方文档中@Repeatable
中值的使用。
测试
注解使用方法
public class AnnotationClass { @Value("hello") @Value("world") public void test(String var1, String var2) { System.out.println(var1 + " " + var2); } }
测试用例
// 获取使用`@Value`注解的`test`方法,并打印这个方法上的注解长度和信息 @Test public void testValue() { Method[] methods = AnnotationClass.class.getMethods(); for (Method method : methods){ if (method.getName().equals("test")) { Annotation[] annotations = method.getDeclaredAnnotations(); System.out.println(annotations.length); System.out.println(method.getName() + " = " + Arrays.toString(annotations)); } } }
因为test
方法上使用了两个@Value
注解,所以猜测打印注解长度为2,然后打印详情,可是结果并不同。
1
test = [@com.example.annotations.Values(value=[@com.example.annotations.Value(value=hello), @com.example.annotations.Value(value=world)])]
结果显示,test
方法上的注解长度为 1 , 且打印信息为@Values
注解,它的值包含了使用的两个注解。
因此可知在jdk8中,相同注解只是以集合的方式进行了保存,原理并没有变化。
注意事项
一些约束
@Repeatable
所声明的注解,其元注解@Target
的使用范围要比@Repeatable
的值声明的注解中的@Target
的范围要大或相同,否则编译器错误,显示@Repeatable
值所声明的注解的元注解@Target
不是@Repeatable
声明的注解的@Target
的子集
// Value @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String value() default "value"; } // Values @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
错误提示信息:
@Repeatable
注解声明的注解的元注解@Retention
的周期要比@Repeatable
的值指向的注解的@Retention
得周期要小或相同。
周期长度为 SOURCE(源码) < CLASS (字节码) < RUNTIME(运行)
// Value 注意 @Retention的值 @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String value() default "value"; } // Values @Target({ElementType.METHOD}) @Retention(RetentionPolicy.CLASS) public @interface Values { Value[] value(); }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。