定义和反射Annotation类(注解)

文章目录


前言

在写代码的过程中,我们经常会写到注释,以此来提醒代码中的点。但是,这些注释不会被查看,也不在整个代码之中,只能在源代码中进行查看。如果想要在代码运行后获取这些注释内容,这就用到了Annotation类了,也就是注解。


一、定义Annotation类

定义Annotation类,需要用到关键字interface,为了区分接口类型,需要在前面加上"@"符号。@interface这个关键字也隐含着继承了java.lang.Annotation接口

定义Annotation类格式:

java 复制代码
public @interface MyAnnotation{
    //权限修饰符 @interface 注解名称{}
}

实操展示:

java 复制代码
public @interface MyAnnotation{
    String value() default "";
}

String为注解内容的类型 value()为自定义名称的注解内容参量 default为设定默认值

二、反射Annotation类

1.元注解

元注解,即为JAVA的API库中最基础的注解。元注解为我们在自定义创建注解时,对这些自定义注解进行规范,用好这些元注解,才能使我们创建的注解发挥到应有的功能。(在用到元注解的时候,需要添加java.lang.annotation.*包

以下是部分元注解的说明表格:

|-------------|----------------------------------------------------------------------------------------|
| 元注解 | 功能描述 |
| @Decumented | 指示某一类型的注释通过javadoc和类似默认工具进行文档化 |
| @Inherited | 指示注释类型被自动继承 |
| @Retention | 指示注释类型的注释要保留多久 |
| @Taraget | 指示注释类型所适用的程序元素的种类 |
| @Deprecated | 在java源码中被@Deprecated修饰的类、方法、变量等表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等。标记不想使用的类,方法,变量,可以看作废案。 |
[部分元注解解读]

在以上表格中,我们想自定义注解,那么用的最频繁的元注解为@Retention(自定义注解会不会在源代码的class文件中,还是乃至扩大到jvm的运行过程)和@Target(自定义注解是给注解、类、接口、枚举、构造方法、成员变量、枚举参数、方法、包等专门地进行注解)。

以下是@Retention和@Target元注解的介绍,不知下面介绍如何实战,具体使用方法请看实操展示 。

@Retention元注解负责管理自定义注解的注解范围, 如果想要反射注解,即获取到注解的信息,必须将@Retention设置为自定义注解在运行代码时加载到JVM中,调用RUNTIME枚举常量

以下是@Retention元注解中的枚举类RetentionPolicy中的枚举常量:

|---------|----------------------------------------------------------------------|
| 枚举常量 | 说明 |
| SOURCE | 表示不编译Annotation到class文化中,注解有效范围最小,甚至小于注释,不能反射zhu'j'e |
| CLASS | 表示编译Annotation到class文件中,但是在运行时不加载Annotation到JVM中,会导致无法反射注解,不能获取到注解信息 |
| RUNTIME | 表示在运行时加载Anntation到JVM中,有效范围最大哦,可以反射注解,获取到注解信息 |
[枚举类RetentionPolicy中的枚举常量]

如果要反射注解,获取到注解信息,我们一定要在自定义注解类上@Retention设置为RUNTIME

使用方法:

java 复制代码
@Retention(RentionPolicy.枚举常量);

@Target元注解负责管理自定义注解的注解对象, 即该自定义注解是给谁添加注解。

以下是@Target元注解中的枚举类ElementType中的枚举常量

|-----------------|----------------------------|
| 枚举常量 | 说明 |
| ANNOTATION_TYPE | 表示用于Annotation类型 |
| TYPE | 表示用于类、接口和枚举,以及Annotation类型 |
| CONSTRUCTOR | 表示用于构造方法 |
| FIELD | 表示用于成员变量和枚举常量 |
| METHOD | 表示用于方法 |
| PARAMETER | 表示用于参数 |
| LOCAL_VARLABLE | 表示用于局部变量 |
| PACKAGE | 表示用于包 |
[枚举类ElementType中的枚举常量]

使用方法:

java 复制代码
@Target(ElementType.枚举常量)

(1)以上枚举常量限制自定义注解的注解对象是谁。

(2)在代码中,注解都是放在被注解对象的上一行的。

2.反射注解

**反射注解,即在运行时获取代码注解的信息。**要获取注解的信息,提供了以下方法:

|--------------------------------------------|--------------------|
| 方法 | 功能描述 |
| isAnnotationPresent(Class annotationClass) | 查看是否添加了指定的注解,返回布尔值 |
| getAnnotation(Class annotationClass) | 获得指定的注解 |
| getAnnotations() | 获得所有的注解的数组 |
[反射注解的方法]

注意:使用以上方法反射注解的前提是,注解类标记为 @Retention(RentionPolicy.RUNTIME) 即注解加载到JVM

**实操展示:**先自定义几个注解,丰富注解内容,然后创建一个Demo类。Demo类中添加构造方法,成员属性,成员变量等,这些内容都要被自定义注解进行注释。最后在main静态方法中使用上述反射注解的方法,实现获取注解信息的功能。

自定义的成员变量注解:

java 复制代码
import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationField {
    String value() default "默认值";    //说明成员变量的含义
    boolean enable() default false;    //说明成员变量是否被废除
}

自定义的构造方法注解:

java 复制代码
import java.lang.annotation.*;

@Target(ElementType.CONSTRUCTOR)    //注解对象为构造方法
@Retention(RetentionPolicy.RUNTIME)    //添加至运行JVM里
public @interface AnnotationConstructors {
    String name() default "";    //解释构造方法
}

自定义的方法注解:

java 复制代码
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationMethod{
    String explain() default "";    //explain参数解释方法是干什么的
}

**default关键字 指定参数的默认值。**在无人为因素下进行注解,其值都为default默认值

Demo类:

java 复制代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo3 {

    @AnnotationField(value = "姓名")
    public String name;

    @Deprecated
    @AnnotationField(value = "身份号码",enable = true)
    public int id;
    
    @AnnotationConstructors(name = "这个构造方法在解释自己")
    public Demo3(){
        System.out.println("这是一个构造方法");
    }
    
    @AnnotationMethod(explain = "这是一个加法运算函数")
    public int add(int a,int b){
        return a+b;
    }


    public static void main(String[] args) {
        Demo3 demo3 = new Demo3();
        Class c = demo3.getClass();
        Field field[] = c.getDeclaredFields();
        for(int i=0;i<field.length;i++){
            if(field[i].isAnnotationPresent(AnnotationField.class)==true){
                System.out.println("----------------------------------------------");
                AnnotationField af=field[i].getAnnotation(AnnotationField.class);
                System.out.println("成员变量:"+field[i].getName()+" 被 @AnnotationField 注解过");
                System.out.println("注解内容为:"+af.value());
                System.out.println("该成员变量是否被废除:"+af.enable());
            }
        }

        Constructor constructor;
        try {
            constructor = c.getConstructor();
            if(constructor.isAnnotationPresent(AnnotationConstructors.class)==true){
                AnnotationConstructors ac=(AnnotationConstructors)constructor.getAnnotation(AnnotationConstructors.class);
                System.out.println("----------------------------------------------");
                System.out.println("构造方法"+constructor.getName()+" 被 @AnnotationConstructor 注解过");
                System.out.println("注解内容为:"+ac.name());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }

        try {
            Method method = c.getMethod("add",int.class,int.class);
            AnnotationMethod am = (AnnotationMethod)method.getAnnotation(AnnotationMethod.class);
            if(method.isAnnotationPresent(AnnotationMethod.class)){
                System.out.println("----------------------------------------------");
                System.out.println("方法"+method.getName()+"被 @AnnotationMethod 注解过");
                System.out.println("注解内容为:"+am.explain());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }

    }
}

运行结果:

如图所示,Demo类中的成员变量、构造方法、方法都被解释了出来,解释清楚这些东西都是什么,便于其他程序员查看理解,注解的使用便利了团队之间的协作,当然注释也能起到这样的效果,只是注解可以直接在控制台中查看。


总结

以上就是创建自定义注解,使用注解,反射注解要讲的内容,本文仅仅简单介绍了注解的使用,而注解便利了我们团队合作,促进彼此的代码可读性,标注内容避免重复"造轮子"。有补充或者更正的内容,欢迎读者在评论区中留言。

相关推荐
The Future is mine34 分钟前
Python计算经纬度两点之间距离
开发语言·python
Enti7c34 分钟前
HTML5和CSS3的一些特性
开发语言·css3
腥臭腐朽的日子熠熠生辉40 分钟前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
爱吃巧克力的程序媛42 分钟前
在 Qt 创建项目时,Qt Quick Application (Compat) 和 Qt Quick Application
开发语言·qt
ejinxian42 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之1 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
俏布斯1 小时前
算法日常记录
java·算法·leetcode
独好紫罗兰1 小时前
洛谷题单3-P5719 【深基4.例3】分类平均-python-流程图重构
开发语言·python·算法
27669582921 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿