getannotations() 不返回继承的注解,因为 java 反射 api 明确区分直接声明与继承注解:它仅返回当前类显式声明、@retention(runtime) 且 @target(type) 的注解,不查父类或接口;@inherited 仅限类继承且条件严格,需手动递归获取继承注解。

Class.getAnnotations() 只返回该类**直接声明**(即显式写在类定义上的)且**保留策略为 RUNTIME** 的注解,**不包含继承自父类或接口的注解**,也不返回 @Retention 为 SOURCE 或 CLASS 的注解。
为什么 getAnnotations() 不返回继承的注解?
Java 的反射 API 设计上将“继承注解”和“直接声明注解”明确区分:
- getAnnotations():仅获取当前类自身 @Retention(RUNTIME) + @Target(TYPE) 的直接注解(不查父类、不查接口)
- getDeclaredAnnotations():同上,但还包括 @Retention 非 RUNTIME 的注解(只要在源码中声明了),仍不继承
- Java 规范中,注解默认不继承 —— 即使父类有 @Inherited 元注解,也只对 类级别、RUNTIME 保留、且被 @Inherited 标记 的注解生效,且仅作用于 子类本身(不传递到接口实现类或间接子类)
如何获取“继承的注解”?需手动向上遍历
Java 没有内置方法一键获取“所有继承来的注解”,必须自己递归检查父类和接口。关键点:
- 只考虑 @Retention(RUNTIME) 注解(否则运行时不可见)
- 父类注解可通过
clazz.getSuperclass()向上追溯,直到 Object - 接口注解需用
clazz.getInterfaces()获取所有直接实现的接口,并递归其父接口 - @Inherited 只影响类继承(即子类能否看到父类的该注解),不影响接口实现或方法/字段继承
实用工具方法示例(获取含继承的全部 RUNTIME 类注解)
以下方法返回当前类及其所有父类、直接/间接实现接口上声明的 @Retention(RUNTIME) 类注解(去重,按声明位置优先级:本类 > 父类 > 接口):
public static Set<annotation> getAllRuntimeTypeAnnotations(Class> clazz) {
Set<annotation> all = new LinkedHashSet();
// 当前类
Collections.addAll(all, clazz.getAnnotations());
// 父类链(跳过 Object)
for (Class> sup = clazz.getSuperclass(); sup != null && sup != Object.class; sup = sup.getSuperclass()) {
Collections.addAll(all, sup.getAnnotations());
}
// 所有接口(含父接口,递归收集)
collectInterfaces(clazz, all);
return all;
}
<p>private static void collectInterfaces(Class> clazz, Set<annotation> all) {
for (Class> itf : clazz.getInterfaces()) {
Collections.addAll(all, itf.getAnnotations());
collectInterfaces(itf, all); // 递归父接口
}
}</annotation></p></annotation></annotation>
注意:@Inherited 的真实作用范围很窄
很多人误以为 @Inherited 能让子类“自动继承”父类的所有注解。实际上它只对满足以下条件的注解生效:
- 注解本身标注了 @Inherited
- 该注解用于 类声明(@Target(ElementType.TYPE))
- 保留策略为 RUNTIME
- 仅当子类 没有在自身声明同名注解 时,才能通过 getAnnotations() 看到父类那个注解
- 不适用于接口、方法、字段;也不传递给实现类的接口注解
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











