定义和反射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类中的成员变量、构造方法、方法都被解释了出来,解释清楚这些东西都是什么,便于其他程序员查看理解,注解的使用便利了团队之间的协作,当然注释也能起到这样的效果,只是注解可以直接在控制台中查看。


总结

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

相关推荐
天下皆白_唯我独黑2 分钟前
php 使用qrcode制作二维码图片
开发语言·php
小灰灰__2 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭5 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
小远yyds7 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
何曾参静谧19 分钟前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++
程序媛小果26 分钟前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林31 分钟前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el
q567315231 小时前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono