Java 反射篇(二)注解 API 总结
JDK 1.5 引入了注解,其主要用途如下:
- 生成文档,通过代码里标识的元数据生成 javadoc 文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
Annotation
首先,注解也是一种 class
,所有注解都默认继承自通用接口:java.lang.annotation.Annotation
:
从上图可见,JDK 提供的元注解(meta annotation)如下:
1 |
其中,@Native
、@Documented
、@Inherited
是一个“标记注解”,没有成员。
常用元注解的作用如下:
@Inherited
@Inherited
用于定义子类是否可继承父类定义的注解。仅针对 @Target(ElementType.TYPE)
类型的注解有效,并且仅针对 class
的继承,对 interface
的继承无效。注意:
- 因此
interface
上标注的注解,无法被 JDK Proxy 动态代理生成的类所继承。 - 也因此 Spring AOP 的切点表达式
@annotation(...)
无法切到基于 JDK Proxy 的动态代理类。
https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html
Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class’s superclass will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached. If no superclass has an annotation for this type, then the query will indicate that the class in question has no such annotation.
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
@Target
@Target
用于定义注解能够被标注于源码的哪些位置。可用字段参考 ElementType
枚举。
JDK 8 扩展了注解的上下文,现在注解几乎可以加到任何地方:局部变量、泛型类、⽗类与接⼝的实现,就连⽅法的异常也能添加注解。
JDK 8 引入的这两个枚举如下:
ElementType.TYPE_PARAMETER
用于标注泛型的类型参数。ElementType.TYPE_USE
用于标注各种类型。
@Retention
@Retention
用于定义注解的生命周期。可用字段参考下面的 RetentionPolicy
枚举源码,常用的是 RUNTIME
类型:
1 | /** |
@Repeatable
JDK 8 引入了 @Repeatable
,表示该注解是否可重复标注。配套引入的还有为 AnnotatedElement
接口新增了两个方法 getAnnotationsByType
、getDeclaredAnnotationsByType
。
AnnotatedElement
读取运行时(@Retention(RetentionPolicy.RUNTIME)
)的注解,需要用到反射 API。java.lang.reflect.AnnotatedElement
接口提供了一组方法,用于获取注解信息:
1 | // 判断某个注解是否存在 |
由于下列类都实现了该接口,因此都拥有这些方法获取注解信息:
1 | java.lang.Class |
举个例子,看下哪些情况通过反射可以拿到注解(或拿不到):
注解如下:
1 |
|
例子一:
1 |
|
例子二:
1 |
|
AnnotatedType
JDK 8 引入了 java.lang.reflect.AnnotatedType
:
类、字段、方法、构造方法相应增加了一组方法用于获取 AnnotatedType
:
Class
1
2AnnotatedType getAnnotatedSuperclass()
AnnotatedType[] getAnnotatedInterfaces()Field
1
AnnotatedType getAnnotatedType()
Method
1
2
3
4AnnotatedType getAnnotatedReturnType()
AnnotatedType[] getAnnotatedParameterTypes()
AnnotatedType[] getAnnotatedExceptionTypes()
AnnotatedType getAnnotatedReceiverType()Constructor
1
2
3
4AnnotatedType getAnnotatedReturnType()
AnnotatedType[] getAnnotatedParameterTypes()
AnnotatedType[] getAnnotatedExceptionTypes()
AnnotatedType getAnnotatedReceiverType()
参考
API: