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


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

    自定义注解

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

    /**
     * 自定义注解
     *
     * @author 10765
     */
    public @interface MyAnnotate {
        // 定义属性times,表示次数,默认值为1
        int times() default 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

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

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

    @Retention注解

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

    public enum RetentionPolicy {
        /**
         * 编译器将丢弃注释
         */
        SOURCE,
    
        /**
         * 注解将由编译器记录在类文件中,但不需要在运行时由 VM 保留。这是默认行为。
         */
        CLASS,
    
        /**
         * 注解将由编译器记录在类文件中,并由 VM 在运行时保留,以便可以反射方式读取它们。
         */
        RUNTIME
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    实例

    先创建一个学生系统的操作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......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    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);
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

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

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

    在这里插入图片描述

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

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

    在这里插入图片描述

  • 相关阅读:
    ubuntu18.04安装gtsam
    Vue3中的Ref与Reactive:深入理解响应式编程
    【half done】剑指offer53:在排序数组中查找数字
    PageHelper基础知识
    VIRTIO-SCSI代码分析(2)VIRTIO 驱动分析
    怒刷LeetCode的第4天(Java版)
    File中文件改名
    Ph.D,一个Permanent head Damage的群体
    GraphGPT: Graph Instruction Tuning for Large Language Models
    python+停车管理系统 毕业设计-附源码271400
  • 原文地址:https://blog.csdn.net/qq_42108331/article/details/130846670