@Inherited仅改变反射查找路径,不使子类真正拥有父类注解;需同时满足:注解类型声明@Inherited、@Target(TYPE)、@Retention(RUNTIME)、子类通过extends继承,否则getAnnotation()无法查到父类注解。

@Inherited 不会让子类“拥有”父类注解,它只改变反射查询时的查找路径——仅当调用 getAnnotation() 或 isAnnotationPresent() 时,JVM 才会沿 extends 链向上搜索,且前提是注解本身被正确设计。
必须同时满足的四个硬性条件
缺一不可,否则注解不会出现在子类反射结果中:
- 自定义注解类型上明确声明了
@Inherited - 该注解只标注在类(
ElementType.TYPE)上,不能标在方法、字段、参数或接口上 - 注解的保留策略是
@Retention(RetentionPolicy.RUNTIME) - 子类通过
extends显式继承父类;implements、组合、代理均无效
为什么 getDeclaredAnnotations() 永远看不到父类注解
getDeclaredAnnotations() 的语义就是“只返回当前类字节码里显式声明的注解”,它不走任何继承链。哪怕父类有 @Inherited 注解,子类的 class 文件里也不会多出一条注解记录。这是 JVM 反射规范的明确约定,不是 bug,而是行为边界。
想判断逻辑上是否继承了某个注解,应统一使用:
立即学习“Java免费学习笔记(深入)”;
clazz.isAnnotationPresent(YourAnno.class)clazz.getAnnotation(YourAnno.class)
这两个方法内部已自动处理向上查找逻辑。
常见失效场景一目了然
以下情况加了 @Inherited 也完全不起作用:
- 注解标在接口上,实现类无法继承(Java 不支持接口注解向实现类传递)
- 注解标在父类方法上,子类重写后调用
method.getAnnotations()拿不到 - 注解的
@Retention是SOURCE或CLASS,运行时根本不可见 - 子类自己也声明了同类型的注解,会覆盖继承来的值(
getAnnotations()返回的是子类声明 + 继承组合,但同类型只取子类的)
多层继承与抽象类完全支持
只要继承链干净(如 C extends B extends A),且 A 类上的注解满足前述四条件,C 就能通过 getAnnotation() 查到 A 的注解。抽象类和普通类在继承机制中无差别——关键不在是否可实例化,而在是否处于 extends 路径上。
注意:即使子类同时 extends Parent 又 implements Interface,JVM 只追溯 Parent → Object 这一条线,接口路径被完全忽略。


















