@Repeatable元注解的用法

在同一个元素上,标记两个相同类型的注解,会导致编译失败。

1@Target({ElementType.TYPE}) 2@Retention(RetentionPolicy.RUNTIME) 3public @interface Value { 4 String value(); 5} 6 7// 编译报错,不能标记多个 8@Value(value = "1") 9@Value(value = "2") 10public class Source {}

@Repeatable 是 JDK1.8 增加的元注解,可以解决注解可以多次标记的问题。

如何声明

在注解上标记 @Repeatable 元注解,设置值为当前注解的集合注解,这个注解理论上来说没有其它的意义,仅仅是为了满足语法要求。

1@Target({ElementType.TYPE}) 2@Retention(RetentionPolicy.RUNTIME) 3@Repeatable(Values.class) 4public @interface Value { 5 String value(); 6} 7 8@Target({ElementType.TYPE}) 9@Retention(RetentionPolicy.RUNTIME) 10public @interface Values { 11 Value[] value(); 12}

如何使用

1// 编译通过 2@Value(value = "1") 3@Value(value = "2") 4public class Source {}

如何解析

标记了 @Repeatable 的注解,在解析时与普通注解不太一样。JDK 会根据注解数量进行区别解析。

  • 如果标记一个,则解析为 @Value
  • 如果标记多个,则解析为 @Values
1@Value(value = "1") 2// @Value(value = "2") 3public class Source { 4 public static void main(String[] args) throws Exception { 5 Annotation[] annotations = Source.class.getAnnotations(); 6 Arrays.stream(annotations).forEach(System.out::println); 7 } 8} 9 10// 输出:@Value(value=1) 11// 打开注释,输出:@Values(value=[@Value(value=1),@Value(value=2)])

因为 @Values 理论上是一个辅助型注解,没有实际的意义,所以在解析过程中,如果能够忽略掉,而只针对 @Value 这个我们实际使用的注解进行解析会更直观一点。

getAnnotationsByType 方法的使用

JDK 提供了 getAnnotationsByType 方法,忽略掉 @Values,收集所有的 @Value 注解作为一个数组进行返回,如果没有,则返回空数组。

1@Value(value = "1") 2// @Value(value = "2") 3public class Source { 4 public static void main(String[] args) throws Exception { 5 Annotation[] annotations = Source.class.getAnnotationsByType(Value.class); 6 Arrays.stream(annotations).forEach(System.out::println); 7 } 8} 9 10// 输出:@Value(value=1) 11// 打开注释,输出:@Value(value=1),@Value(value=2)

与 @Inherited 元注解结合使用

为 @Value 及 @Values 添加 @Inherited 元注解,使其拥有被继承的功能

1@Target({ElementType.TYPE}) 2@Retention(RetentionPolicy.RUNTIME) 3@Repeatable(Values.class) 4@Inherited 5public @interface Value { 6 String value(); 7} 8 9@Target({ElementType.TYPE}) 10@Retention(RetentionPolicy.RUNTIME) 11@Inherited 12public @interface Values { 13 Value[] value(); 14}

父类与子类分别声明 @Value 注解,观察是继承及重写的情况

1@Value("1") // 代码 1 2// @Value("2") // 代码 2 3public class Base {} 4 5// @Value("3") // 代码 3 6// @Value("4") // 代码 4 7public class Child extends Base { 8 public static void main(String[] args) throws Exception { 9 Annotation[] annotations = Child.class.getAnnotations(); 10 Arrays.stream(annotations).forEach(System.out::println); 11 } 12}

这里需要再次强调解析的规则

  • 如果标记一个,则解析为 @Value
  • 如果标记多个,则解析为 @Values

子类解析的 @Value 注解会重写父类解析的 @Value 注解,子类解析的 @Values 注解会重写父类解析的 @Values 注解,而解析的 @Value 注解与 @Values 注解则互相不关联。

场景一:只有代码 1

父类标记了一个 @Value 注解,解析为 @Value 注解,子类继承父类

1@Value(value=1)

场景二:代码 1、2

父类标记了多个 @Value 注解,解析为 @Value 注解,子类继承父类

1@Values(value=[@Value(value=1),@Value(value=2)])

场景三:代码 1、3

父类与子类都只标记了一个注解,都解析为 @Value 注解,子类覆盖父类

1@Value(value=3)

场景四:代码 1、2、3

父类标记了多个 @Value 注解,解析为 @Values 注解,子类标记了一个 @Value 注解,解析为 @Value 注解,@value 与 @Values 互不干扰,子类继承父类的 @Values 注解,子类自己的 @Value 注解也独自生效

1@Value(value=3) 2@Values(value=[@Value(value=1),@Value(value=2)])

场景五:代码 1、3、4

父类标记了一个 @Value 注解,解析为 @Value 注解,子类标记了多个 @Value 注解,解析为 @Values 注解,@value 与 @Values 互不干扰,子类继承父类的 @Value 注解,子类自己的 @Values 注解也独自生效

子类继承父类的 @Value 注解,子类自己被解析为 @Values 注解

1@Value(value=1) 2@Values(value=[@Value(value=3),@Value(value=4)])

场景四:代码 1、2、3、4

父类与子类都标记了多个注解,都解析为 @Values 注解,子类覆盖父类

1@Values(value=[@Value(value=3),@Value(value=4)])

getAnnotationsByType 方法的使用

getAnnotations、getAnnotation、isAnnotationPresent 方法解析过程是同一套体系,getAnnotationsByType 方法的解析过程则是另外一套体系。

不管怎么组合,只要子类标记了 @Value 注解,就会覆盖父类中的标记,如果子类未标记,则会继承父类中的标记。跟 @Values 注解完全无关。

1@Value("1") // 代码 1 2// @Value("2") // 代码 2 3public class Base {} 4 5@Value("3") // 代码 3 6@Value("4") // 代码 4 7public class Child extends Base { 8 public static void main(String[] args) throws Exception { 9 Annotation[] annotations = Child.class.getAnnotationsByType(Value.class); 10 Arrays.stream(annotations).forEach(System.out::println); 11 } 12} 13// 输出:@Value(value=3),@Value(value=4)
点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

JAVA注解

一、初步认识注解1.为什么学习注解?答: a.能够读懂别人写的代码,特别是框架相关的代码        b.让编程更加简洁,代码更加清晰2.注解概念?答:java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法二、java中的常见注解1.JDK自带注解:        a、@Override

SpringBoot自定义注解

JDK1.5起开始提供了4个元注解:@Target、@Retention、@Documented、@Inherited。何谓元注解?就是注解的注解。@Target({ElementType.PARAMETER,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@

SpringBoot自定义注解

JDK1.5起开始提供了4个元注解:@Target、@Retention、@Documented、@Inherited。何谓元注解?就是注解的注解。@Target({ElementType.PARAMETER,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@

Spring @ModelAttribute注解用法

之前项目中并自己并没有怎么使用到过@ModelAttribute这个注解,接手一个老项目的时候发现项目中大量使用@ModelAttribute这个注解,在这里就整理下这个注解常用的方式,也为自己做个记录,以免久了不用又忘记了@ModelAttribute使用大致有有两种,一种是是直接标记在方法上,一种是标记在方法的参数中,两种标记方法产生的效果也各不相

Java元注解

1、注解数据类型注解是写在.java文件中,使用@interface作为关键字,所以注解也是Java的一种数据类型,从广泛的定义来说,Class、Interface、Enum、Annotation都属于Class类型。2、元注解在创建注解的时候,需要使用一些注解来描述自己创建的注解(即注解的注解),就是写在@interfac