@inherited仅对类继承有效,要求注解同时满足@inherited、@target(elementtype.type)、@retention(runtime),其作用仅为反射时沿superclass链向上查找,不复制注解且不适用于接口、方法或字段。

只对类继承有效,其他一概不管
@Inherited 的作用范围非常窄——它只影响 类(class)之间通过 extends 实现的直接继承关系。接口实现(implements)、接口继承(extends interface)、方法重写、字段定义、参数或局部变量上的注解,哪怕加了 @Inherited,也完全不会传递。JVM 规范明确限定:它“only causes annotations to be inherited from superclasses;annotations on implemented interfaces have no effect”。这意味着,哪怕你把一个带 @Inherited 的注解标在接口上,实现类调用 getAnnotation() 一定返回 null。
三个条件缺一不可
想让子类通过 Class.getAnnotation() 拿到父类的注解,自定义注解必须同时满足:
- 自身声明了
@Inherited -
@Target(ElementType.TYPE)—— 只能用于类、接口、枚举,不能只限 METHOD 或 FIELD -
@Retention(RetentionPolicy.RUNTIME)—— SOURCE 或 CLASS 级别在运行时不可见,反射查不到
三者少一个,子类就无法“看到”父类的该注解。比如 Spring 的 @Service 没加 @Inherited,即使父类被它标记,子类也反射不到。
不是复制,只是向上查找
@Inherited 不会让子类字节码里真正多出这个注解,它只是改变了反射行为:调用 getAnnotation() 时,JVM 会自动沿 getSuperclass() 链向上搜索,直到找到第一个匹配的注解或到达 Object。而 getDeclaredAnnotation() 始终只看当前类自己写的注解,完全不查父类。这种机制支持多层继承(A → B → C),但只走单根 extends 路径,不进接口、不跨组合。
方法和字段注解必须手动扫描
父类方法上的注解,无论是否加 @Inherited,子类重写后调用 getMethod().getAnnotation() 必定为 null。字段同理,子类定义同名字段只是遮蔽(hiding),不会继承父类字段的任何注解。要获取“继承链上最近的方法注解”,得自己写工具逻辑:
- 从目标类开始,用
getDeclaredMethod()查当前类的方法注解 - 没找到就调用
getSuperclass(),重复查找 - 如需支持接口方法,还得递归处理
getInterfaces()及其所有父接口
Spring 的 AnnotationUtils.findAnnotation() 就是这样实现的——@Inherited 原生不提供这类能力。











