@inherited不是注解自动复制机制,而是反射时沿继承链向上查找的约定;需同时满足:注解声明@inherited且@target(type)、标注在父类上、@retention(runtime)、子类未显式声明同名注解,才可通过getannotation()获取父类注解。

@Inherited 不是让注解“自动复制”到子类的魔法开关,它只是一种反射行为约定——当满足特定条件时,子类调用 getAnnotation() 才能向上查到父类的注解。理解这点,才能避开绝大多数踩坑场景。
必须同时满足的四个前提
子类能通过 clazz.getAnnotation(MyAnno.class) 拿到父类注解,需全部成立:
- 自定义注解本身声明了
@Inherited(且仅对ElementType.TYPE有效) - 该注解实际标注在父类上,而非方法、字段或接口
- 注解的保留策略为
@Retention(RetentionPolicy.RUNTIME) - 子类未在自身类声明处显式使用同一注解(否则会覆盖继承路径)
哪些情况它完全不工作
@Inherited 的限制非常刚性,以下情形一律无效:
- 注解标在方法上:子类重写该方法后,
getMethod(...).getAnnotation()始终返回null - 类实现接口:哪怕接口用了
@Inherited注解,实现类也查不到 - 注解标在字段或参数上:与继承无关,JVM 规范明确排除支持
- 注解保留策略是
SOURCE或CLASS:运行时根本不可见
继承链不是“传递”,而是“查找”
子类 class 文件里不会多出任何注解字节码。所谓“继承”,本质是 JVM 在反射调用时沿 getSuperclass() 向上遍历,直到 Object。这意味着:
- A → B → C 的三层继承中,C 能拿到 A 的
@Inherited注解,是因为查找路径覆盖了整条extends链 - 但如果中间 B 类自己也加了同名注解,而该注解类型没声明
@Inherited,那么 C 就无法从 B 继承——它只能靠 A 传递;若 A 也没加@Inherited,C 就彻底拿不到
真正需要跨层级感知注解时怎么办
业务若要求子类运行时知晓祖先类或实现接口上的注解(比如权限校验、配置合并),不能依赖 @Inherited,应手动扫描:
- 递归调用
clazz.getSuperclass(),逐层检查getAnnotation() - 展开所有接口:
clazz.getInterfaces()返回的每个接口,再递归其getInterfaces() - 统一收集所有匹配注解实例,按需合并或取优先级最高的
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











