您现在的位置是:首页 >技术杂谈 >自定义注解和@Target、@Retention注解的使用网站首页技术杂谈

自定义注解和@Target、@Retention注解的使用

何中应 2024-06-22 12:01:02
简介自定义注解和@Target、@Retention注解的使用

说明:注解可以理解为另一种形式的配置,可用于在类上、方法上等,标志是“@”,如重写方法上的“@Override”就是一种注解。这里我通过一个实例,来介绍自定义注解和java元注解(@Target、@Retention)的使用

自定义注解

在idea中鼠标右键创建一个类,选择“Annotation”可创建一个注解;我这里创建了一个MyAnnotate注解,设置了一个int类型的times属性,默认值是1
在这里插入图片描述

/**
 * 自定义注解
 *
 * @author 10765
 */
public @interface MyAnnotate {
    // 定义属性times,表示次数,默认值为1
    int times() default 1;
}

@Target注解

java元注解的一种,表示当前注解可使用的类型,查看java源码,可以看到有以下待选:

public enum ElementType {
    // 类、接口(包括注释类型)或枚举声明
    TYPE,
    
    // 字段声明(包括枚举常量)
    FIELD,

    // 方法声明
    METHOD,

    // 形式参数声明
    PARAMETER,

    // 构造函数声明
    CONSTRUCTOR,

    // 局部变量声明
    LOCAL_VARIABLE,

    // 注解类型声明
    ANNOTATION_TYPE,

    // 包声明
    PACKAGE,

    /**
     * 类型参数声明
     *
     * 自JDK1.8出现
     */
    TYPE_PARAMETER,

    /**
     * 使用类型
     *
     * 自JDK1.8出现
     */
    TYPE_USE,

    /**
     * 模块声明
     *
     * 自JDK9出现
     */
    MODULE
}

如上面我自定义的注解,我想只能用于方法上,就可以设置为“@Target(ElementType.METHOD)”

/**
 * 自定义注解
 * @author 10765
 */
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
public @interface MyAnnotate {
    // 定义属性times,表示次数,默认值为1
    int times() default 1;
}

@Retention注解

表示当前注解存活,或者说可使用的阶段,默认是存活在字节码阶段。查看java源码,有以下待选:

public enum RetentionPolicy {
    /**
     * 编译器将丢弃注释
     */
    SOURCE,

    /**
     * 注解将由编译器记录在类文件中,但不需要在运行时由 VM 保留。这是默认行为。
     */
    CLASS,

    /**
     * 注解将由编译器记录在类文件中,并由 VM 在运行时保留,以便可以反射方式读取它们。
     */
    RUNTIME
}

我先不作设置,用实例执行以下我的注解,看下效果

实例

先创建一个学生系统的操作Demo类,并在方法上添加注解,以后使用,想达到的效果是仅执行带有注解的方法,并且根据注解的times值,执行对应的次数

/**
 * 学生操作
 */
public class StudentOperate {
    public void save() {
        System.out.println("save running......");
    }

    public void delete() {
        System.out.println("delete running......");
    }

    @MyAnnotate
    public void update() {
        System.out.println("update running......");
    }

    @MyAnnotate(times = 3)
    public void get() {
        System.out.println("get running......");
    }
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        // 获取StudentOperate类的Class对象
        Class stuOperateClass = Class.forName("com.essay02.StudentOperate");

        // 获取StudentOperate类的所有方法对象
        Method[] methodObjs = stuOperateClass.getDeclaredMethods();
        
        // 生成一个Class对象的实例化对象
        Object stuOpObj = stuOperateClass.newInstance();

        // 遍历所有方法对象
        for (Method methodObj : methodObjs) {
            // 如果有MyAnnotate注解,就进行操作,否则不作处理
            if (methodObj.isAnnotationPresent(MyAnnotate.class)) {
                // 获取注解对象
                MyAnnotate annotation = methodObj.getAnnotation(MyAnnotate.class);

                // 获取注解的属性值times
                int times = annotation.times();

                // 根据属性值循环执行该方法
                for (int i = 0; i < times; i++) {
                    methodObj.invoke(stuOpObj);
                }
            }
        }
    }
}

可以看到,没有执行结果。分析:因为注解的保留策略(@Retention)没有设置,默认保留到字节码阶段,运行时丢弃了,故没有达到预期结果。
在这里插入图片描述
查看一下程序的字节码文件
在这里插入图片描述
设置注解保留策略为运行时,再执行一遍

/**
 * 自定义注解
 * @author 10765
 */
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
// 指定该注解的保留策略为:保留到运行阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotate {
    // 定义属性times,表示次数,默认值为1
    int times() default 1;
}

在这里插入图片描述

最后再试下,保留策略设置为源代码,再运行下查看字节码文件中注解是否还存在

/**
 * 自定义注解
 * @author 10765
 */
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
// 指定该注解的保留策略为:保留到源码阶段
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotate {
    // 定义属性times,表示次数,默认值为1
    int times() default 1;
}

在这里插入图片描述

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。