@Inherited仅对类生效:子类通过getAnnotations()可继承父类的该注解,但不适用于接口、方法、字段等;需配合@Retention(RUNTIME)且仅限单继承链。

@Inherited只对类生效
这个元注解的作用范围非常明确:它仅影响被标记在类上的注解。如果一个自定义注解用@Inherited修饰,且该注解被加在某个父类上,那么它的子类在通过反射调用getAnnotations()时,能“看到”这个注解;但如果该注解加在接口、方法、字段或参数上,哪怕用了@Inherited,也不会产生继承效果。
子类不会自动“拥有”该注解
这里容易误解:@Inherited并不是让子类的字节码里真正写入那个注解,而是改变反射查询行为。具体来说:
- 调用
clazz.getAnnotations()时,若clazz自身没声明该注解,JVM会沿着继承链向上查找,直到找到第一个带该注解的父类(前提是该注解本身被@Inherited标记) - 调用
clazz.getDeclaredAnnotations()则只看当前类显式声明的注解,完全不查父类 - 子类的class文件中并不会多出任何注解信息,只是反射API做了隐式回溯
必须配合RUNTIME保留策略
即使加了@Inherited,如果注解自身的@Retention设为SOURCE或CLASS,运行时也拿不到——因为前者编译即丢,后者不进反射API。要让继承性在运行期可见,注解必须声明为:
@Retention(RetentionPolicy.RUNTIME)
否则,isAnnotationPresent(YourAnno.class)永远返回false,无论父类有没有、有没有@Inherited。
接口和抽象类不参与此机制
Java的类继承是单根的,而接口实现是多路径的。@Inherited的设计只考虑extends关系,不处理implements。也就是说:
- 父接口上有@Inherited修饰的注解,实现类不会继承到
- 抽象父类上的注解可以被具体子类继承(只要满足前述条件)
- 即使子类同时继承父类又实现某接口,也只有父类路径起作用

















