@inherited仅在类继承链中通过class.getannotation()触发向上查找,且须同时满足注解声明@inherited、@target(type)、@retention(runtime)三条件;方法、字段、接口均不支持继承;需手动遍历继承链获取注解。

@Inherited 并不是让子类“自动拥有”父类注解的复制机制,它只是在调用 Class.getAnnotation() 时,触发一次向上查找——仅限类继承链,且必须满足三个硬性条件。
只对类生效,且必须三条件齐备
一个注解要被子类通过反射读到,必须同时满足:
- 该注解自身声明了
@Inherited -
@Target(ElementType.TYPE),即只能标注在类、接口、枚举上 -
@Retention(RetentionPolicy.RUNTIME),确保运行时可读
缺一不可。比如 Spring 的 @Service 没加 @Inherited,哪怕父类标了它,子类也查不到。
方法和字段注解完全不继承
无论是否加 @Inherited,方法或字段上的注解都不会传递给子类:
- 子类重写父类方法后,
getMethod().getAnnotation()返回null,因为 JVM 不合并父类方法的注解 - 子类定义同名字段,只是遮蔽(hiding)父类字段,不会继承其注解
- 字段注解的元数据只绑定在声明它的 Field 对象上,无法跨类传播
接口实现和接口继承均无效
@Inherited 对接口场景完全不起作用:
- 接口上标注了带
@Inherited的注解,实现类调用getAnnotation()仍返回null - 接口 A 继承接口 B,B 上的注解不会传给 A
- 哪怕接口和实现类都用了相同注解类型,也属于各自独立声明,无继承关系
替代方案:手动遍历继承链
当需要真正获取语义相关的注解(如权限、数据源、事务),不能依赖 @Inherited,应主动扫描:
- 对类:循环调用
clazz.getSuperclass(),每层都试getAnnotation(),直到null或Object - 对方法:从子类方法开始,用
getDeclaredMethod()查当前类;没找到就向上找父类同签名方法 - 对接口:需展开
getInterfaces(),递归处理每个接口及其父接口,注意避免重复和循环引用
Spring 的 AnnotationUtils.findAnnotation() 就是这样实现的。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











