@Inherited是唯一影响注解继承的元注解,仅对类级别且运行时保留的注解生效,通过getClass().getAnnotation()可获取父类注解,但不适用于接口、代理或门面类。

Java元注解本身不参与“类继承”,但通过 @Inherited 可控制注解是否沿类继承链向下传递——这是唯一与继承直接相关的元注解。它只对标注在类上的注解生效,且仅影响子类能否通过 getAnnotation() 获取父类注解,对接口、方法、字段等无效。
@Inherited 的真实作用边界
很多人误以为 @Inherited 能让注解“自动跨类传播”,其实它有严格限制:
- 仅适用于 类级别(@Target(ElementType.TYPE)) 的注解
- 仅当子类直接继承父类(非实现接口或代理/门面包装)时才生效
- 子类调用
getClass().getAnnotation(MyAnno.class)才能拿到父类的注解;若用getDeclaredAnnotation()则拿不到 - 不适用于接口:即使接口上有 @Inherited 注解,实现类也不会继承它
为什么门面类/代理类拿不到注解?
比如你有一个 @DataRecordSupport 标注在真实工厂类上,而对外暴露的是一个门面类(如 ExportDocumentFacade),后者只是委托调用。此时:
- 门面类自身没加该注解
- @Inherited 对它无效(因为不是继承关系,而是组合/委托)
-
facade.getClass().getAnnotation(DataRecordSupport.class)返回 null
这不是 bug,而是设计使然:注解绑定的是声明位置,不是运行时语义。
立即学习“Java免费学习笔记(深入)”;
实战技巧:绕过 @Inherited 局限的可靠方案
当需要跨装饰器、代理、门面传递类型级元数据时,推荐以下做法:
-
把注解读取逻辑下沉到接口 default 方法:定义
ExportDocumentFactory接口,提供default Class>[] getSupportedDataRecordClasses(),内部遍历this.getClass()的继承链查找注解 -
配合 @Inherited + 显式向上扫描:在 default 方法中手动调用
getSuperclass()循环查找,弥补 @Inherited 不覆盖代理场景的短板 - 避免在接口上标注 @Inherited 注解:它不起作用,反而造成误解;真正要继承的注解必须标在父类上
- 运行时注解务必设 @Retention(RetentionPolicy.RUNTIME):否则反射读不到,@Inherited 也就无从谈起
@Target 和 @Retention 是 @Inherited 的前提
光写 @Inherited 不够,注解本身必须满足两个条件才能被继承:
- @Target(ElementType.TYPE):确保它能标在类上
- @Retention(RetentionPolicy.RUNTIME):保证运行时可通过反射访问
缺一不可。例如下面这个注解是无效的继承候选:
❌ 错误示例@Inherited<br>@Target(ElementType.METHOD)<br>@Retention(RetentionPolicy.CLASS)<br>@interface MyAnno {}
它既不能标在类上,又无法在运行时读取,@Inherited 完全失效。


















