Inherited和Repeatable元注解组合使用
在使用Repeatable元注解后,我们会发现父类上使用Value注解标记同样也是不能获取到注解属性值,那么我们此时会有一个疑问,如何在父类上使用注解同样能在子类中获取注解属性内容呢?此时我们可能会联想到Inherited元注解,那么我们开始尝试下我们的猜想!
基础类准备:
Value注解类
@Repeatable(Values.class) @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); }
Values注解类
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
Parent类
@Value(value = "parent-1") @Value(value = "parent-2") public class Parent { }
Child类
@Value(value = "child-1") @Value(value = "child-2") public class Child extends Parent { }
测试类
public class AnnoMain { public static void main(String[] args) { Class<Child> clazz = Child.class; if (clazz.isAnnotationPresent(Value.class)) { Value valueAnnotation = clazz.getAnnotation(Value.class); System.out.println("Value annotation present: " + valueAnnotation.value()); } if (clazz.isAnnotationPresent(Values.class)) { System.out.print("Values annotation present: "); Values dataAnnotation = clazz.getAnnotation(Values.class); Value[] values = dataAnnotation.value(); for (Value value : values) { System.out.print(value.value() + "\t"); } } } }
我们首先对Value注解类添加@Inherited元注解,代码如下:
@Inherited @Repeatable(Values.class) @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); }
此时我们会看到在IDE编译器中会有报错提示,如下所示:
此处提示我们在容器注解中不存在必要的@Inherited注解,因此我们在Values注解中也加入@Inherited注解
那么如果我们仅在Values注解中添加@Inherited注解,不在Value注解中添加@Inherited注解会有什么问题呢?
我们先将Value注解恢复原状,代码如下:
@Repeatable(Values.class) @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); }
再在Values注解中添加@Inherited注解,代码如下:
@Inherited @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
此时没有任何的错误信息,那么我们开始调整下Child类信息,再编写一个测试类:
public class Child extends Parent { }
执行测试类,结果如下:
我们会发现,同样父类的多标记内容也全部被打印出来了,那么如果在子类上也添加同多次标记,是否也会像单个标记的情况一样覆盖掉呢?那么接下来我们修改下Child类
@Value(value = "child-1") @Value(value = "child-2") public class Child extends Parent { }
执行测试类,结果如下:
我们会发现,这种容器注解,也跟单次标记的注解一样会覆盖掉父类数据。
那么如果我们父类和子类多次标记个数不一致的情况下,执行出来的结果又会是什么样子呢?我们来修改下Parent类,Child类还是使用基础类,代码如下:
@Value(value = "parent-1") @Value(value = "parent-2") @Value(value = "parent-3") public class Parent { }
执行测试类,结果如下:
我们可以明显看出,多次标记的情况下,不管父类添加多少标记,子类的多次标记都会将父类的多次标记内容覆盖掉。
那么如果一个使用单次标记,一个使用多次标记会是什么样子的呢?
我们来修改下Child和Parent类,代码如下:
Child类
@Value(value = "child-1") public class Child extends Parent { }
Parent类
@Value(value = "parent-1") @Value(value = "parent-2") @Value(value = "parent-3") public class Parent { }
执行测试类,结果如下:
我们从结果可以看出,一次跟多次标记会全部都输出,也就是说父子类要么都是一次标记,要么都是多次标记,子类才会将注解内容覆盖掉!
接下来,我们做另一个猜想,容器注解Values使用@Inherited注解,但是Value注解不使用@Inherited注解,是否会影响到单次标记的注解呢?
那么我们修改下Parent和Child类,代码如下:
public class Child extends Parent { } @Value(value = "parent-1") public class Parent { }
执行测试类,结果如下:
我们会发现,子类并没有办法获取到父类的注解属性内容,也就说容器注解的继承并不会影响到容器注解关联的注解。那么我们再在Value注解上添加@Inherited注解。
修改Value注解,代码如下:
@Inherited @Repeatable(Values.class) @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); }
执行测试类,结果如下:
我们可以从这些执行结果中看出,Value添加@Inherited注解,Values容器注解不添加@Inherited注解,容器注解会受到影响,编译不通过,反之则正常,但是单次标记不会继承父类的注解信息内容。