理解注解中的@Inherited

6,619
@Inherited:
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。



注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,
方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。
如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:
检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。


看下面的例子:
Java代码 收藏代码
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Inherited
  4. public @interface ATable {
  5. public String name() default "";
  6. }
  7. @Target(ElementType.TYPE)
  8. @Retention(RetentionPolicy.RUNTIME)
  9. public @interface BTable {
  10. public String name() default "";
  11. }
  12. @ATable
  13. public class Super {
  14. private int superx;
  15. public int supery;
  16. public Super() {
  17. }
  18. private int superX(){
  19. return 0;
  20. }
  21. public int superY(){
  22. return 0;
  23. }
  24. }
  25. @BTable
  26. public class Sub extends Super{
  27. private int subx;
  28. public int suby;
  29. private Sub()
  30. {
  31. }
  32. public Sub(int i){
  33. }
  34. private int subX(){
  35. return 0;
  36. }
  37. public int subY(){
  38. return 0;
  39. }
  40. }
  41. public class TestMain {
  42. public static void main(String[] args) {
  43. Class<Sub> clazz = Sub.class;
  44. System.out.println("============================Field===========================");
  45. System.out.println(Arrays.toString(clazz.getFields()));
  46. System.out.println(Arrays.toString(clazz.getDeclaredFields())); //all + 自身
  47. System.out.println("============================Method===========================");
  48. System.out.println(Arrays.toString(clazz.getMethods())); //public + 继承
  49. //all + 自身
  50. System.out.println(Arrays.toString(clazz.getDeclaredMethods()));
  51. System.out.println("============================Constructor===========================");
  52. System.out.println(Arrays.toString(clazz.getConstructors()));
  53. System.out.println(Arrays.toString(clazz.getDeclaredConstructors()));
  54. System.out.println("============================AnnotatedElement===========================");
  55. //注解DBTable2是否存在于元素上
  56. System.out.println(clazz.isAnnotationPresent(BTable.class));
  57. //如果存在该元素的指定类型的注释DBTable2,则返回这些注释,否则返回 null。
  58. System.out.println(clazz.getAnnotation(BTable.class));
  59. //继承
  60. System.out.println(Arrays.toString(clazz.getAnnotations()));
  61. System.out.println(Arrays.toString(clazz.getDeclaredAnnotations())); ////自身
  62. }
  63. }



分析下这段代码,这里定义了两个annotion,其中ATable使用了@Inherited, BTable没有使用
@Inherited,类Super和类Sub分别使用了ATable和BTable这两个注解,并且Sub类 继承Super类。


这段程序的运行结果如下:
Java代码 收藏代码
  1. ============================Field===========================
  2. [public int annotion.inherit.Sub.suby, public int annotion.inherit.Super.supery]
  3. [private int annotion.inherit.Sub.subx, public int annotion.inherit.Sub.suby]
  4. ============================Method===========================
  5. [public int annotion.inherit.Sub.subY(), public int annotion.inherit.Super.superY(), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
  6. [private int annotion.inherit.Sub.subX(), public int annotion.inherit.Sub.subY()]
  7. ============================Constructor===========================
  8. [public annotion.inherit.Sub(int)]
  9. [private annotion.inherit.Sub(), public annotion.inherit.Sub(int)]
  10. ============================AnnotatedElement===========================
  11. true
  12. @annotion.inherit.BTable(name=)
  13. [@annotion.inherit.ATable(name=), @annotion.inherit.BTable(name=)]
  14. [@annotion.inherit.BTable(name=)]




getFields()获得某个类的所有的公共(public)的字段,包括父类。
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,
但是不包括父类的申明字段。 同样类似的还有getConstructors()和getDeclaredConstructors(),
getMethods()和getDeclaredMethods()。

因此:Field的打印好理解,因为sub是super类的子类,会继承super的类
同样method和constructor的打印也是如此。

clazz.getAnnotations()可以打印出当前类的注解和父类的注解
clazz.getDeclaredAnnotations()只会打印出当前类的注解

如果注解ATable把@Inherit去掉。那么后面四行的输出结果为:
Java代码 收藏代码
  1. true
  2. @annotion.inherit.BTable(name=)
  3. [@annotion.inherit.BTable(name=)]
  4. [@annotion.inherit.BTable(name=)]

无法获取到@ATable的注解,
也就是说注解和普通类的区别是如果一个子类想获取到父类上的注解信息,
那么必须在父类上使用的注解上面 加上@Inherit关键字