Java 的类本身具备继承的能力,可以继承一个类,也可以实现多个接口。那么产生了一个疑问:在父类或者接口上标记的注解,在解析子类时是否可以解析得到?从而使用子类在继承父类的时候,同时继承注解标记所拥有的能力。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
String value() default "";
}
@Value("1")
public class Base {}
public class Child extends Base {
public static void main(String[] args) throws Exception {
Annotation[] annotations = Child.class.getAnnotations();
Arrays.stream(annotations).forEach(System.out::println);
}
}
// 输出为空
继承
通过上面的代码可以看出,通过子类是无法直接解析出父类上标记的注解的。JDK 提供了 @Inherited 元注解,只要在注解上添加这个元注解,就可以实现通过子类解析出父类上标记的注解。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Value {
String value() default "";
}
@Value("1")
public class Base {}
public class Child extends Base {
public static void main(String[] args) throws Exception {
Annotation[] annotations = Child.class.getAnnotations();
Arrays.stream(annotations).forEach(System.out::println);
}
}
// 输出:@Value(value=1)
通过上面的代码可以看到,仅仅是加了一行 @Inherited,父类上的注解就可以被子类直接解析得到。
同样的代码,我们使用接口再运行一次
@Value("1")
public interface IBase {}
public class Child implements IBase {
public static void main(String[] args) throws Exception {
Annotation[] annotations = Child.class.getAnnotations();
Arrays.stream(annotations).forEach(System.out::println);
}
}
// 输出为空
通过上面的代码可以看到,标记的接口上注解解析不了。其实不光接口上的注解无法继承,成员变量、方法等其它元素都无法继承,也就是说,所谓继承,只能继承 class 上的注解,其它都无法继承。
重写
子类可以继承父类上的注解,子类本身也可以标记注解。如果子类与父类同时标记的同一个注解,会产生怎么样的结果呢?
@Value("1")
public class Base {}
@Value("3")
public class Child extends Base {
public static void main(String[] args) throws Exception {
Annotation[] annotations = Child.class.getAnnotations();
Arrays.stream(annotations).forEach(System.out::println);
}
}
// 输出 @Anno1(value=3)
通过上面的代码可以看出,子类与父类标记相同的注解,子类会覆盖父类。 这与子类实现父类中的方法是一样的效果。