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

示例代码仓库地址

相关推荐
兔头?几秒前
使用JDK21新特性虚拟线程时遇到的坑
java
FullStackGeek14 分钟前
微信缴费APIV3接入
后端
灯澜忆梦21 分钟前
【Go Zap 日志库】#1 |快速上手 + 配置详解
开发语言·后端·golang
m0_5873830026 分钟前
无人自助拼豆系统从需求分析到落地部署全流程实战开发指南
java·经验分享·后端·struts·小程序·架构·需求分析
a努力。28 分钟前
四维解析Agent记忆架构:从零实战LangGraph长期记忆
java·开发语言·数据库
碧海银沙音频科技研究院30 分钟前
炬芯ATS308X的扩音器:麦克风到扬声器直通功能实现
java·linux·运维
Rain的Java大神之路36 分钟前
被问麻了!Function Calling、MCP、Skill 到底啥关系?一张图讲透三层架构,附 Java 生产落地全流程+30个坑
java·后端·ai编程
Wang's Blog36 分钟前
Java 项目部署之 Docker工具快速入门: Docker Compose 初识与安装
java·开发语言·docker
niucloud-admin43 分钟前
JAVA V6 多商户商城 开发文档——项目启动
java·开发语言·python
众链网络1 小时前
Agent 重试的工程解法:幂等、断点续跑与熔断怎么落地
java·前端·数据库·人工智能