AnnotatedElement接口剖析
AnnotatedElement接口
首先对Java中的AnnotatedElement接口进行说明,AnnotatedElement定义了在Java中可以如何通过反射的方式获取元素上的注解。
其主要的方法如下:
scss
// 判断注解是否存在
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
// 根据注解类型获取元素上的注解
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 获取元素上的所有注解
Annotation[] getAnnotations();
// 根据注解类型获取元素上所有同类型的注解
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
// 根据注解类型获取元素上直接存在的注解
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
// 根据注解类型获取元素上直接存在的所有注解
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
// 获取元素上所有直接存在或间接存在的注解
Annotation[] getDeclaredAnnotations();
看完上面的注释,应该还是对于直接存在与间接存在有一点困惑,我们接着往下看。
根据注解在元素上的形式被分为四种类型
- 直接存在
- 间接存在
- 存在(包括直接存在和间接存在)
- 关联
直接存在
顾名思义,注解以直接存在的形式存在时就是注解直接存在。如下代码所示
kotlin
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@DirectlyPresentAnnotationDemo.DirectPresentAnnotation
public class DirectlyPresentAnnotationDemo {
public static void main(String[] args) {
// 获取元素上直接存在的所有注解
Annotation[] annotations = DirectlyPresentAnnotationDemo.class.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
// DirectPresentAnnotation("defaultValue")
System.out.println(annotation);
}
// 根据注解类型获取直接存在的注解
Annotation annotation = DirectlyPresentAnnotationDemo.class.getDeclaredAnnotation(DirectPresentAnnotation.class);
// DirectPresentAnnotation("defaultValue")
System.out.println(annotation);
}
@Retention(RetentionPolicy.RUNTIME)
public @interface DirectPresentAnnotation {
String value() default "defaultValue";
}
}
间接存在
它表示注解是以一种重复注解组合的方式声明在元素之上的。如下代码所示:
java
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 注解间接存在
*
*/
@IndirectlyPresentAnnotationDemo.RepetableAnnotations(value = {
@IndirectlyPresentAnnotationDemo.RepetableAnnotation("1"),
@IndirectlyPresentAnnotationDemo.RepetableAnnotation("2")
})
public class IndirectlyPresentAnnotationDemo {
public static void main(String[] args) {
// 获取间接存在的注解
Annotation[] annotations = IndirectlyPresentAnnotationDemo.class.getDeclaredAnnotationsByType(RepetableAnnotation.class);
for (Annotation annotation : annotations) {
// RepetableAnnotation("1")
// RepetableAnnotation("2")
System.out.println(annotation);
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface RepetableAnnotations {
RepetableAnnotation[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepetableAnnotations.class)
public @interface RepetableAnnotation {
String value() default "defaultValue";
}
}
存在
这种形式表示注解是直接声明于元素上,或者以继承的方式存在于元素之上。如下代码所示:
kotlin
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class PresentAnnotationDemo extends SuperClass implements SuperInterface{
public static void main(String[] args) {
Annotation[] annotations = PresentAnnotationDemo.class.getAnnotations();
for (Annotation annotation : annotations) {
// SuperClassAnnotation("superClass")
System.out.println(annotation);
}
Annotation annotation = PresentAnnotationDemo.class.getAnnotation(SuperClassAnnotation.class);
// SuperClassAnnotation("superClass")
System.out.println(annotation);
Annotation interfaceAnnotation = PresentAnnotationDemo.class.getAnnotation(SuperInterfaceAnnotation.class);
// null,接口上的注解无法被继承
System.out.println(interfaceAnnotation);
}
/**
* @Inherited 表示注解可被继承,注意,只有在类上使用才会被继承,在接口、方法、成员变量上使用不会被继承
*/
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SuperClassAnnotation {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SuperInterfaceAnnotation {
String value();
}
}
@PresentAnnotationDemo.SuperClassAnnotation("superClass")
class SuperClass {
}
@PresentAnnotationDemo.SuperInterfaceAnnotation("superInterface")
interface SuperInterface {
}
关联
注解直接存在或间接存在于元素上,或是以继承的方式来自于父类 。注意它与存在的区别,多了一种间接存在的场景。这种类型的就不举例了,前面的代码如果都看了那么就很容易弄懂。
最后总结一下AnnotatedElement的几个方法在不同注解存在场景下的适用情况
返回值类型 | 方法 | 直接存在 | 间接存在 | 存在 | 关联 |
---|---|---|---|---|---|
T | getAnnotation(Class) | √ | |||
Annotation[] | getAnnotations() | √ | |||
T[] | getAnnotationsByType(Class) | √ | |||
T | getDeclaredAnnotation(Class) | √ | |||
Annotation[] | getDeclaredAnnotations() | √ | |||
T[] | getDeclaredAnnotationsByType(Class) | √ | √ |
AnnotatedElement在JDK中的类结构
AnnotatedType类型说明
AnnotatedType是提供了对泛型类型参数、泛型类型上界、泛型类型下界、数组元素类型等复杂类型使用中的注解的访问。
在 Java 8 及其之后的版本中,是可以在泛型上使用注解的。这种特性被称为类型注解(Type Annotations),允许将注解放在任何使用类型的地方,包括泛型类型参数、泛型通配符、以及数组类型等。
以下是一个如何在泛型上使用注解的简单例子:
java
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedType;
import java.util.List;
public class GenericTypeAnnotationDemo {
public void processList(@NonEmpty List<String> strings) {
}
public static void main(String[] args) throws NoSuchMethodException {
// 通过反射获取方法参数的注解信息
AnnotatedType[] annotatedParameterTypes = GenericTypeAnnotationDemo.class
.getMethod("processList", List.class)
.getAnnotatedParameterTypes();
AnnotatedType annotatedParameterType = annotatedParameterTypes[0];
Annotation[] annotations = annotatedParameterType.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof NonEmpty) {
System.out.println("Parameter has @NonEmpty annotation");
}
}
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NonEmpty {
}
}