AnnotatedElement接口剖析

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();

看完上面的注释,应该还是对于直接存在与间接存在有一点困惑,我们接着往下看。

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

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

直接存在

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

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

示例代码仓库地址

相关推荐
Rust研习社5 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒6 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro7 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax7 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH7 小时前
Koa和Express的区别
后端
MariaH7 小时前
Koa框架的使用
后端
luckdewei8 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某10 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy10 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom10 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github