AnnotatedElement接口剖析

135 阅读3分钟

AnnotatedElement接口剖析

AnnotatedElement接口

首先对Java中的AnnotatedElement接口进行说明,AnnotatedElement定义了在Java中可以如何通过反射的方式获取元素上的注解

其主要的方法如下:

// 判断注解是否存在
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();

根据注解在元素上的形式被分为四种类型

  1. 直接存在
  2. 间接存在
  3. 存在(包括直接存在和间接存在)
  4. 关联

直接存在

顾名思义,注解以直接存在的形式存在时就是注解直接存在。如下代码所示

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";
    }
}

间接存在

它表示注解是以一种重复注解组合的方式声明在元素之上的。如下代码所示:

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";
    }
​
}

存在

这种形式表示注解是直接声明于元素上,或者以继承的方式存在于元素之上。如下代码所示:

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的几个方法在不同注解存在场景下的适用情况

返回值类型方法直接存在间接存在存在关联
TgetAnnotation(Class)
Annotation[]getAnnotations()
T[]getAnnotationsByType(Class)
TgetDeclaredAnnotation(Class)
Annotation[]getDeclaredAnnotations()
T[]getDeclaredAnnotationsByType(Class)

AnnotatedElement在JDK中的类结构

AnnotatedElementUML.png

AnnotatedType类型说明

AnnotatedType是提供了对泛型类型参数、泛型类型上界、泛型类型下界、数组元素类型等复杂类型使用中的注解的访问。

在 Java 8 及其之后的版本中,是可以在泛型上使用注解的。这种特性被称为类型注解(Type Annotations),允许将注解放在任何使用类型的地方,包括泛型类型参数、泛型通配符、以及数组类型等。

以下是一个如何在泛型上使用注解的简单例子:

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 {
​
    }
​
}

示例代码仓库地址