@Inherited仅在特定条件下使类级注解支持继承式反射查找:需同时满足注解被@Inherited修饰、@Target(ElementType.TYPE)、@Retention(RUNTIME),且仅对直接父类的类注解生效,不适用于方法、字段、接口等。

@Inherited 不会让子类“自动拥有”父类的注解声明——它只是让 某些特定条件下的类级注解 在调用 Class.getAnnotation() 时,能顺着继承链向上查找一次。这不是复制、不是继承、更不是“自动带上”,而是一种反射层面的查询优化机制。
必须满足的三个硬性条件
只有同时满足以下全部条件,@Inherited 才起作用:
- 被
@Inherited修饰的,是一个自定义注解(不能直接在类或方法上写@Inherited) - 该自定义注解自身声明了
@Target(ElementType.TYPE),且仅用于标注类 - 该自定义注解声明了
@Retention(RetentionPolicy.RUNTIME),确保运行时可通过反射读取
它只对类有效,其他地方一律失效
很多人误以为加了 @Inherited 就能“全局继承”,实际限制极严:
- 父类方法上的注解,无论是否带
@Inherited,子类重写后调用getMethod().getAnnotation()一定返回null - 接口上定义的注解,哪怕也用了
@Inherited,实现类 完全不会继承 - 字段、参数、构造器、局部变量等位置的注解,
@Inherited对它们没有任何影响 - 如果父类是通过组合(如 Spring 的
@Service)间接获得注解,而不是直接声明,那子类查不到
真正生效时的表现
假设你定义了如下注解:
@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 也能拿到 A 上的
@MyConfig
想查方法/字段/接口注解?得自己遍历
Java 原生不提供跨层级注解查找能力。要获取“继承链上最近的方法注解”,需手动递归:
- 从目标类开始,调用
getDeclaredMethod()查当前类声明的方法 - 若没找到注解,再调用
getSuperclass()获取父类,重复查找 - 如需支持接口,还要额外处理
getInterfaces()并递归其父接口(注意避免循环) - Spring 的
AnnotationUtils.findAnnotation()就是这样实现的

















