@inherited仅在类继承且满足三个硬性条件时生效:注解自身标有@inherited、@target(elementtype.type)、@retention(retentionpolicy.runtime),否则不向上查找;方法、字段、接口等场景均无效。

@Inherited 不会让子类“自动拥有”父类的注解,它只影响 Class.getAnnotation() 在类继承链上的查找行为——仅当满足全部硬性条件时,反射调用才会向上查找一次父类的类级注解。
必须同时满足的三个前提
缺一不可,否则 @Inherited 完全不生效:
- 自定义注解自身必须标注 @Inherited(不能直接在类上写 @Inherited)
- 该注解需声明 @Target(ElementType.TYPE),且只能用于类(不能标在方法、字段、接口等位置)
- 该注解需声明 @Retention(RetentionPolicy.RUNTIME),确保运行时可通过反射读取
只对类继承有效,其他场景一律无效
常见误解多源于边界不清。实际限制非常严格:
- 父类方法上加了带 @Inherited 的注解,子类重写后调用 getMethod().getAnnotation() 一定返回 null
- 接口上用了 @Inherited 注解,实现类完全不会继承——哪怕接口和实现类都满足所有条件
- 字段、构造器、参数、局部变量等位置的注解,@Inherited 对它们无任何作用
- 若父类是通过组合(如 Spring 的 @Service 标在基类上,子类未显式标注),子类 Class 对象查不到该注解
真实生效时的行为表现
假设定义如下注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyConfig {
String value() default "";
}
并这样使用:
@MyConfig("parent")
class Parent {}
class Child extends Parent {}
此时:
- Child.class.getAnnotation(MyConfig.class) 返回非空(值为 "parent")
- Child.class.getDeclaredAnnotation(MyConfig.class) 仍返回 null(子类自己没写)
- 支持多层继承:A → B → C,C 调用 getAnnotation 也能拿到 A 上的 @MyConfig
替代方案:需要跨层级查方法或字段注解时
Java 原生不提供继承式方法/字段注解查找。要获取“继承链上最近的注解”,必须手动递归:
- 从目标类开始,用 getDeclaredMethod() 查当前类声明的方法
- 若未找到注解,调用 getSuperclass() 获取父类,重复查找
- 如需支持接口,还需额外处理 getInterfaces() 并递归其父接口(注意避免循环引用)
- Spring 的 AnnotationUtils.findAnnotation() 就是按此逻辑实现的
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











