Inherited 前面也介绍过,这个注解作用是注解其他注解,让注解具有继承的特性。但是继承是有条件的。 下面是摘自javaDOC上的一段话
1 Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
中文意思如下
1 请注意,如果带有继承特性的注解使用在其他元素而不是类上,则注解的继承特性是没有效果的。还要注意,这个元注解只会从父类继承注解;实现接口上的注解没有作用。
具体示例 标记在类上的继承情况 自定义一个带有继承特性的注解
1 2 3 4 5 @Inherited @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface BatchExec { String value () ; }
被注解的父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @BatchExec(value = "类名上的注解") public abstract class ParentClass { @BatchExec(value = "父类的abstractMethod方法") public abstract void abstractMethod () ; @BatchExec(value = "父类的doExtends方法") public void doExtends () { System.out.println(" ParentClass doExtends ..." ); } @BatchExec(value = "父类的doHandle方法") public void doHandle () { System.out.println(" ParentClass doHandle ..." ); } }
子类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class SubClass1 extends ParentClass { @Override public void abstractMethod () { System.out.println("子类实现父类的abstractMethod抽象方法" ); } @Override public void doHandle () { System.out.println("子类覆盖父类的doHandle方法" ); } }
使用反射来测试子类是否继承了父类的注解,测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class MainTest1 { public static void main (String[] args) throws SecurityException, NoSuchMethodException { Class<SubClass1> clazz = SubClass1.class; if (clazz.isAnnotationPresent(BatchExec.class)) { BatchExec cla = clazz.getAnnotation(BatchExec.class); System.out.println("类:子类可继承" ); } else { System.out.println("类:子类不能继承到父类类上Annotation" ); } Method method = clazz.getMethod("abstractMethod" , new Class [] {}); if (method.isAnnotationPresent(BatchExec.class)) { BatchExec ma = method.getAnnotation(BatchExec.class); System.out.println("子类实现抽象方法:子类可继承" ); } else { System.out.println("子类实现抽象方法:没有继承到父类抽象方法中的Annotation" ); } Method methodOverride = clazz.getMethod("doExtends" , new Class [] {}); if (methodOverride.isAnnotationPresent(BatchExec.class)) { BatchExec ma = methodOverride.getAnnotation(BatchExec.class); System.out.println("子类未实现方法:子类可继承,注解读取='" + ma.value() + "'" ); } else { System.out.println("子类未实现方法:没有继承到父类doExtends方法中的Annotation" ); } Method method3 = clazz.getMethod("doHandle" , new Class [] {}); if (method3.isAnnotationPresent(BatchExec.class)) { BatchExec ma = method3.getAnnotation(BatchExec.class); System.out.println("子类覆盖父类的方法:继承到父类doHandle方法中的Annotation“); } else { System.out.println(" 子类覆盖父类的方法:没有继承到父类doHandle方法中的Annotation"); } // 子类重写的方法 Method method4 = clazz.getMethod(" doHandle2", new Class[] {}); if (method4.isAnnotationPresent(BatchExec.class)) { BatchExec ma = method4.getAnnotation(BatchExec.class); System.out.println(" 子类未实现方法doHandle2:子类可继承"); } else { System.out.println(" 子类未实现方法doHandle2:没有继承到父类doHandle2方法中的Annotation"); } } }
结果:
1 2 3 4 5 类:子类可继承, 子类实现抽象方法:没有继承到父类抽象方法中的Annotation 子类未实现方法: 子类可继承 子类覆盖父类的方法:没有继承到父类doHandle方法中的Annotation 子类未实现方法doHandle2:没有继承到父类doHandle2方法中的Annotation
标记在接口上的继承情况 1 2 3 4 @BatchExec(value = "接口上的注解") public interface Parent { void abstractMethod () ; }
接口的继承类
1 2 3 4 5 6 7 8 9 10 11 public class ParentClass3 { public void abstractMethod () { System.out.println("ParentClass3" ); } @BatchExec(value = "父类中新增的doExtends方法") public void doExtends () { System.out.println(" ParentClass doExtends ..." ); } }
该继承类的注解可见测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MainTest3 { public static void main (String[] args) throws SecurityException, NoSuchMethodException { Class<ParentClass3> clazz = ParentClass3.class; if (clazz.isAnnotationPresent(BatchExec.class)) { BatchExec cla = clazz.getAnnotation(BatchExec.class); System.out.println("类:子类可继承" ); } else { System.out.println("类:子类不能继承到接口类上Annotation" ); } Method method = clazz.getMethod("abstractMethod" , new Class [] {}); if (method.isAnnotationPresent(BatchExec.class)) { BatchExec ma = method.getAnnotation(BatchExec.class); System.out.println("子类实现抽象方法:子类可继承" ); } else { System.out.println("子类实现抽象方法:没有继承到接口抽象方法中的Annotation" ); } Method methodOverride = clazz.getMethod("doExtends" , new Class [] {}); if (methodOverride.isAnnotationPresent(BatchExec.class)) { BatchExec ma = methodOverride.getAnnotation(BatchExec.class); System.out.println("子类中新增方法:可被读取注解" ); } else { System.out.println("子类中新增方法:不能读取注解" ); } } }
结果:
1 2 3 类:子类不能继承到接口类上Annotation 子类实现抽象方法:没有继承到接口抽象方法中的Annotation 子类中新增方法:注解读取='父类中新增的doExtends方法
子类的子类注解继承情况 1 2 3 4 5 6 7 8 9 10 public class SubClass3 extends ParentClass3 { @Override public void abstractMethod () { System.out.println("子类实现父类的abstractMethod抽象方法" ); } }
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MainTest33 { public static void main (String[] args) throws SecurityException, NoSuchMethodException { Class<SubClass3> clazz = SubClass3.class; if (clazz.isAnnotationPresent(BatchExec.class)) { BatchExec cla = clazz.getAnnotation(BatchExec.class); System.out.println("类:子类可继承" ); } else { System.out.println("类:子类不能继承到父类类上Annotation" ); } Method method = clazz.getMethod("abstractMethod" , new Class [] {}); if (method.isAnnotationPresent(BatchExec.class)) { BatchExec ma = method.getAnnotation(BatchExec.class); System.out.println("子类实现抽象方法:子类可继承" ); } else { System.out.println("子类实现抽象方法:没有继承到父类抽象方法中的Annotation" ); } Method methodOverride = clazz.getMethod("doExtends" , new Class [] {}); if (methodOverride.isAnnotationPresent(BatchExec.class)) { BatchExec ma = methodOverride.getAnnotation(BatchExec.class); System.out.println("子类未实现方法:子类可继承" ); } else { System.out.println("子类未实现方法:没有继承到父类doExtends方法中的Annotation" ); } } }
结果:
1 2 3 类:子类不能继承到父类类上Annotation 子类实现抽象方法:没有继承到父类抽象方法中的Annotation 子类未实现方法:子类可继承
总结 从上面可以看出,被@Inherited
标记过的注解,标记在类上面可以被子类继承,标记在方法上,如果子类实现了此方法,则不能继承此注解,如果子类是继承了方法,而没有重新实现方法则可以继承此方法的注解。
Repetable 允许在同一申明类型(类,属性,或方法)的多次使用同一个注解
一个简单的例子 java 8之前也有重复使用注解的解决方案,但可读性不是很好,比如下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public @interface Authority { String role () ; } public @interface Authorities { Authority[] value(); } public class RepeatAnnotationUseOldVersion { @Authorities({@Authority(role="Admin"),@Authority(role="Manager")}) public void doSomeThing () { } }
由另一个注解来存储重复注解,在使用时候,用存储注解Authorities来扩展重复注解,我们再来看看java 8里面的做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Repeatable(Authorities.class) public @interface Authority { String role () ; } public @interface Authorities { Authority[] value(); } public class RepeatAnnotationUseNewVersion { @Authority(role="Admin") @Authority(role="Manager") public void doSomeThing () { } }
不同的地方是,创建重复注解Authority时,加上@Repeatable,指向存储注解Authorities,在使用时候,直接可以重复使用Authority注解。从上面例子看出,java 8里面做法更适合常规的思维,可读性强一点