@inherited仅使类级注解支持单层继承:父类标注后子类可反射获取,但不适用于接口、字段、方法,且不支持多层跨级继承(如a→b→c中c无法直接获取a的注解)。

@Inherited 是 Java 中一个特殊的元注解,但它只对类级注解(即作用在类上的注解)生效,且仅支持单层继承传递:父类标注了被 @Inherited 修饰的注解,子类在不显式标注时,可通过反射 getAnnotation() 获取该注解;但接口实现、类组合、多层继承(如 A → B → C)中,C 不会自动“继承”A 的注解(B 要有该注解才行)。
第一步:定义可被继承的自定义注解
必须满足三个条件:用 @Inherited 修饰、@Retention(RetentionPolicy.RUNTIME)、@Target(ElementType.TYPE)。
例如:
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AutoLog {
String value() default "default";
}
⚠️ 注意:@Inherited 对方法、字段上的注解无效;也不影响子类是否“拥有”该注解——它只影响 Class.getAnnotation() 的查找逻辑。
第二步:在父类上使用该注解
直接标注在父类上即可,无需额外操作:
@AutoLog("service")
public class BaseService {
}
子类只要继承它,且未覆盖(重写)该注解,就能通过反射读取到:
public class UserService extends BaseService {
public static void main(String[] args) {
Class<userservice> clazz = UserService.class;
AutoLog ann = clazz.getAnnotation(AutoLog.class);
System.out.println(ann != null); // true
System.out.println(ann.value()); // "service"
}
}
</userservice>
第三步:验证继承边界(常见误区)
- 子接口 不会 继承父接口上的
@Inherited注解(接口不参与@Inherited机制) - 实现接口的类 不会 因为接口有该注解就自动获得
- 如果子类自己也标注了同名注解(即使没加
@Inherited),则以子类的为准,父类注解被屏蔽 - 孙子类(B 继承 A,C 继承 B)能获取到 C 上的注解,也能获取到 B 上的(如果 B 显式标注),但 不能跨级获取 A 的 —— 除非 B 也继承了 A 的注解(即 B 本身没重写,靠继承得来)
第四步:配合注解处理器或 AOP 做实际应用
单纯继承注解没意义,关键是要在运行时触发行为。比如结合 Spring AOP 自动织入日志:
- 定义切点:匹配所有带有
@AutoLog的类中的 public 方法 - AOP 切面中读取类上的
@AutoLog,提取value()作为日志前缀 - 子类方法执行时,即使子类没写
@AutoLog,也能从其父类反射拿到配置
这样就实现了“一套注解配置,子类开箱即用”的效果,避免重复标注。










