• Java自定义注解的实现


    Java自定义注解的实现

    简介

    注解:说明程序的,给计算机看的。

    注释:用文字描述程序的,给程序员看的。

    定义:注解(Annotation),也叫元数据,一种代码级别的说明,它是JDK1.5以后版本引入的一个特性,与类、接口、枚举在同一个层次。可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

    概念描述:

    • JDK1.5之后的新特性
    • 用于说明程序
    • 使用注解:@注解名称

    作用分类:

    • 编写文档:通过代码里标识的注解生成文档
    • 代码分析:通过注解对代码进行分析(利用反射)
    • 编译检查:通过代码里的注解让编译器能够实现基本的编译检查例如Override

    JDK中预定义的一些注解

    • @Override:检测被该注解标注的方法是否是继承自夫类/接口的
    • @Deprecated:表示该注解标注的内容,已过时
    • @SuppressWarnings:压制警告

    自定义注解

    注解的定义规则

    观察预定义注解的源码

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    可以看出,注解的定义方法是

    @元注解
    @元注解
    ....
    public @interface 注解名{
    
    }
    

    其中,元注解可以省略,元注解的概念,我们下面再说。

    注解的本质

    模仿上面定义的方式,创建一个自定义注解

    public @interface MyAnno{
    
    }
    

    使用javac命令编译,查看源码:

    public interface MyAnno extends java.lang.annotation.Annotation{}
    

    所以注解本质上就是一个接口,其默认继承了Annotation接口

    注解中的属性

    注解本质就是一个接口,所以属性本质上就是接口中可以定义的成员方法。

    接口里面能定义的,注解内都可以定义

    属性返回值的要求:

    • 基本数据类型
    • String
    • 枚举
    • 注解
    • 以上的数据类型
    • 不能是void或者包装类型

    下面是定义一个包含属性的注解的声明:

    package cn.rayfoo.common.annotation.validate;
    
    /**
     * @author rayfoo@qq.com
     * @version 1.0
     * <p></p>
     * @date 2020/8/7 11:19
     */
    public @interface NotNull {
    
        int myProp1();
    
        String myProp2();
    
        long[] myProp3();
    
    }
    

    此时,在使用注解的时候,必须给属性赋值

    属性的修饰default

    使用注解时,不需要给注解赋值,可以在属性后加default修饰。不加修饰的为必须指定的内容。

    package cn.rayfoo.common.annotation.validate;
    
    /**
     * @author rayfoo@qq.com
     * @version 1.0
     * <p></p>
     * @date 2020/8/7 11:19
     */
    public @interface NotNull {
    
        int myProp1() default 10;
    
        String myProp2() default "rayfoo";
    
        long[] value();
    
    }
    

    使用带有参数的注解

    数字属性使用{}修饰

    @NotNull(prop2 = "giao",value={1L,2L})
    

    如果有且只有一个必须赋值的属性,并且属性名为value,属性的name可以省略

    @NotNull(value={1L,2L})
    

    数组中如果只有一个元素,大括号可以省略

    @NotNull(value=1L})
    

    带有注解类型属性的使用方式

        @ApiImplicitParams({
                @ApiImplicitParam(name = "name", value = "用户名", required = true, dataType = "String", paramType = "query"),
                @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "query"),
                @ApiImplicitParam(name = "phoneNumber", value = "手机号", required = true, dataType = "String", paramType = "query"),
                @ApiImplicitParam(name = "signature", value = "签名", required = false, dataType = "String", paramType = "query"),
                @ApiImplicitParam(name = "email", value = "邮箱", required = true, dataType = "String", paramType = "query"),
                @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "String", paramType = "query"),
        })
    

    包含枚举属性的注解使用方式

    @RequestMapping(value = "/user",method = HttpMethod.DELETE)
    

    元注解

    元注解就是用于描述注解的注解

    @Target:描述注解能够作用的位置

    下面时target的源码,其只有一个枚举类数组类型的属性ElementType[]

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        /**
         * Returns an array of the kinds of elements an annotation type
         * can be applied to.
         * @return an array of the kinds of elements an annotation type
         * can be applied to
         */
        ElementType[] value();
    }
    

    ElementType取值

    public enum ElementType {
        /** 类和接口上 */
        TYPE,
    
        /** 字段上 */
        FIELD,
    
        /** 方法上 */
        METHOD,
    
        /** 参数上 */
        PARAMETER,
    
        /** 构造上 */
        CONSTRUCTOR,
    
        /** 本地变量上 */
        LOCAL_VARIABLE,
    
        /** 注解上 */
        ANNOTATION_TYPE,
    
        /** 包上 */
        PACKAGE,
    
        /**
         * 类型参数上
         *
         * @since 1.8
         */
        TYPE_PARAMETER,
    
        /**
         * Use of a type
         *
         * @since 1.8
         */
        TYPE_USE
    }
    

    这个可以根据自己的需要,添加合适的修饰。

    @Retention:描述注解能够保留的阶段

    观察源码,可以看出,其只有一个枚举类型的属性

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        /**
         * Returns the retention policy.
         * @return the retention policy
         */
        RetentionPolicy value();
    }
    
    

    RetentionPolicy取值范围

    public enum RetentionPolicy {
        /**
         * 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
         */
        SOURCE,
    
        /**
         * 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
         */
        CLASS,
    
        /**
         * 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;(自定义注解一般都用RUNTIME)
         */
        RUNTIME
    }
    

    @Retention:描述注解能够保留的阶段

    @Documented:描述注解是否能被抽取到API文档中

    加上该注解后,其修饰的注解会被抽取到JavaDoc文档中

    @Inherited:描述注解是否可以被子类继承

    加入此注解后继承了加了此注解修饰的类的子类,也会自动加上该注解修饰的注解

    注解的扫描

    加入注解后,对类没有任何的影响,真正进行操作的是读取注解处,我们可以借助反射中的知识,读取并借助注解的属性进行一些操作。一般配合AOP一起使用。

    field.isAnnotationPresent(注解.class)
    注解 verify = field.getAnnotation(注解.class);
    String name = 注解.name();
    ...判断
    
  • 相关阅读:
    OpenSLAM
    CAD&CG GDC 2018大会论文录用名单
    hdu4328(经典dp用悬线法求最大子矩形)
    hdu3729(二分图)
    hdu 4055(经典问题)
    Codeforces Round #207 (Div. 1) B (gcd的巧妙运用)
    hdu1066(经典题)
    zoj3662(dp)
    zoj3659(经典并查集)
    hdu4565(矩阵快速幂+经典的数学处理)
  • 原文地址:https://www.cnblogs.com/zhangruifeng/p/13454114.html
Copyright © 2020-2023  润新知