• 自定义注解


    注解也被称为元数据,它为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。

    注解是受c#启发,在 javaSE5 中引入的,虽然javaSE5 预先定义了一些注解,但一般来说,主要还是程序员添加新的注解,并按自己的方式使用他们。

    内置注解

    java SE5 内置了三种注解:

    • @Override, 表示当前的方法覆盖超类中的方法。如果拼写错误,或者方法签名对不上被覆盖的方法,编译器就会发出错误提示,
    • @Deprecated, 标记方法被弃用了,如果使用了被它标记的元素,编译器会发出警告信息
    • @SuppressWarnings, 关闭不当的编译器警告信息。

    之外,java还提供了四种注解,专门负责新注解的创建,也被称为元注解

    元注解

    @Target

    用来定义你的注解将用于什么地方,例如用在方法上,类上 还是字段上等, 使用方式: @Target(ElementType.METHOD), 其中 ElementType 的取值有下面几种:

    • CONSTRUCTOR 构造器
    • FIELD 域, 包括 enum 的实例
    • LOCAL_VARIABLE 局部变量
    • METHOD 方法上
    • PACKAGE
    • PAEAMETER 参数
    • TYPE 类, 接口,包括注解类型 或 enum

    @Retention

    表示在什么级别保存该注解的信息,例如源码中,类文件中,或者运行时,使用方式: @Retention(RetentionPolicy.RUNTIME), 其中 RetentionPolicy 的取值有:

    • SOURCE 注解将被编译器丢弃
    • CLASS 注解在class文件中可用,但会被 JVM 丢弃
    • RUNTIME JVM 在运行期也保留注解,因此可以通过反射机制读取注解信息

    @Documented

    将此注解包含在 javadoc中

    @Inherited

    允许子类继承父类中的注解

    编写注解

    一个注解得以工作要有三个要素:

    1. 定义注解
    2. 使用注解
    3. 注解处理器

    下面用一个对象/关系映射功能 ORM的简单例子来展现如何编写自定义注解:

    1. @DBTable 将此注解用于 JavaBean 上,以便生成一个数据库表
    2. @Constrains此注解用于字段上,描述该字段有一些约束,比如不能为空,要唯一等
    3. @SQLString 将此注解用于字段上,会生成一个 varchar 类型的列
    4. @SQLInt 将此注解用于字段上,会生成一个 int 类型的列

    定义注解

    /**
     * 注解定义
     */
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DBTable{
        // 表名, 规定:必须要有一个默认值,
        String name() default "";
    }
    
    /**
     * 字段的约束
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Constraints{
        // 是否是主键
        boolean primary() default false;
        // 是否可以为空
        boolean allowNull() default true;
        // 是否唯一
        boolean unique() default false;
    }
    
    /**
     * 生成 varchar 类型的列
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SQLString{
    
        /**
         *  让value代表 varchar的长度,value 是个比较特殊的名字,在使用该注解的时候,
         *  如果该元素是唯一需要赋值的元素。那么可以简写,无需使用 名———值 语法,而是
         *  @SQLString(30)
         */
        int value() default 0;
        // 列的名字
        String name() default "";
    }
    
    /**
     * 生成 int 类型的列
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SQLInt{
        // 列的名字
        String name() default "";
    }
    
    • 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
    • 47
    • 48
    • 49
    • 50
    • 51

    注解的使用

    /**
     * 注解使用
     */
    @DBTable(name = "users")// 表名是useres
    public class User {
        /**
         * 设置id是主键,唯一, 不能为空
         */
        @Constraints(primary = true, allowNull = false, unique = true)
        @SQLInt
        private int id;
    
        @SQLInt
        private  int age;
    
        @SQLString(20)
        private String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 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

    注解处理器

    /**
     * 注解处理器
     */
    public class TableCreator{
        public String createTableSQLString(Class<?> cl) {
            // 获取类上的 DBTable 注解
            DBTable table = cl.getAnnotation(DBTable.class);
            if(table == null) {
                return "";
            }
            // 获取 DBTable 注解中的 name 参数
            String tableName = table.name();
    
            // 保存所有列名
            List<String> columnNameList = new ArrayList<String>();
            // 反射的方式遍历类中的字段
            for (Field field : cl.getDeclaredFields()) {
                // 列名
                String columnName = "";
    
                // 遍历字段上的注解
                for (Annotation annotation : field.getAnnotations()) {
                    // 如果包含 SQLInt 注解
                    if(annotation instanceof SQLInt) {
                        SQLInt sint = (SQLInt) annotation;
                        if(sint.name().length() == 0) {
                            columnName = field.getName().toLowerCase();
                        }else{
                            // 如果没有设置name属性,就用字段名作为列名
                            columnName = sint.name();
                        }
                        columnName += " INT";
    
                        // 获取字段上的约束类型的注解
                        Constraints con = field.getAnnotation(Constraints.class);
                        columnName += buildConstraints(con);
    
                        // 否则检查是否包含 @SQLString 注解
                    }else if(annotation instanceof SQLString) {
                        SQLString sString = (SQLString) annotation;
                        if(sString.name().length() == 0) {
                            columnName = field.getName().toLowerCase();
                        }else{
                            // 如果没有设置name属性,就用字段名作为列名
                            columnName = sString.name();
                        }
                        // 获取字段长度属性
                        columnName += " VARCHAR(" + sString.value() + ")";
                        // 获取字段上的约束类型的注解
                        Constraints con = field.getAnnotation(Constraints.class);
                        columnName += buildConstraints(con);
                    }
                }
                columnNameList.add(columnName);
            }
    
    
            StringBuilder createConmmand = new StringBuilder("");
            createConmmand.append("CREATE TABLE ").append(tableName).append("(");
    
            int length = columnNameList.size();
            for (int i = 0; i < length; i ++) {
                createConmmand.append("\n    ").append(columnNameList.get(i));
                if(i != length -1){
                    createConmmand.append(",");
                }
            }
    
            createConmmand.append(");");
    
    
            return createConmmand.toString();
        }
    
        public String buildConstraints(Constraints con){
            if(con == null) {
                return "";
            }
            if(!con.allowNull()){
                return " NOT NULL";
            }
            if(con.primary()){
                return " PRIMARY KEY";
            }
            if(con.unique()) {
                return " UNIQUE";
            }
            return "";
        }
    }
    
    public class AnnotationDemo {
    
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> userClass = Class.forName("io.dc.User");
            String sql =  new TableCreator().createTableSQLString(userClass);
            // 直接下面的也行
    //        String sql =  new TableCreator().createTableSQLString(User.class);
            System.out.println(sql);
        }
    }
    
    • 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
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    注解使用注意

    • 不同注解可以组合使用,但同类型的注解不能重复使用
    • 目前注解不支持继承
    • 注解中的属性不能为 null, 本例中的 @SQLString name() 不能为 null, 必须设置 default
    • 注解元素只能一下几种,否则编译器会报错
      • 所有基本类型(int, float, boolean 等)
      • String
      • Class
      • enum
      • Annotation
      • 以上类型的数组

    完整代码

    为了测试方便,把所有类都放在一个文件中了:

    package io.dc;
    
    import java.lang.annotation.*;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * 注解定义
     */
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface DBTable{
        // 表名, 规定:必须要有一个默认值,
        String name() default "";
    }
    
    /**
     * 字段的约束
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Constraints{
        // 是否是主键
        boolean primary() default false;
        // 是否可以为空
        boolean allowNull() default true;
        // 是否唯一
        boolean unique() default false;
    }
    
    /**
     * 生成 varchar 类型的列
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface SQLString{
    
        /**
         *  让value代表 varchar的长度,value 是个比较特殊的名字,在使用该注解的时候,
         *  如果该元素是唯一需要赋值的元素。那么可以简写,无需使用 名———值 语法,而是
         *  @SQLString(30)
         */
        int value() default 0;
        // 列的名字
        String name() default "";
    }
    
    /**
     * 生成 int 类型的列
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface SQLInt{
        // 列的名字
        String name() default "";
    }
    
    
    /**
     * 注解使用
     */
    @DBTable(name = "users")// 表名是useres
    class User {
        /**
         * 设置id是主键,唯一, 不能为空
         */
        @Constraints(primary = true, allowNull = false, unique = true)
        @SQLInt
        private int id;
    
        @SQLInt
        private  int age;
    
        @SQLString(20)
        private String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    /**
     * 注解处理器
     */
    class TableCreator{
        public String createTableSQLString(Class<?> cl) {
            // 获取类上的 DBTable 注解
            DBTable table = cl.getAnnotation(DBTable.class);
            if(table == null) {
                return "";
            }
            // 获取 DBTable 注解中的 name 参数
            String tableName = table.name();
    
            // 保存所有列名
            List<String> columnNameList = new ArrayList<String>();
            // 反射的方式遍历类中的字段
            for (Field field : cl.getDeclaredFields()) {
                // 列名
                String columnName = "";
    
                // 遍历字段上的注解
                for (Annotation annotation : field.getAnnotations()) {
                    // 如果包含 SQLInt 注解
                    if(annotation instanceof SQLInt) {
                        SQLInt sint = (SQLInt) annotation;
                        if(sint.name().length() == 0) {
                            columnName = field.getName().toLowerCase();
                        }else{
                            // 如果没有设置name属性,就用字段名作为列名
                            columnName = sint.name();
                        }
                        columnName += " INT";
    
                        // 获取字段上的约束类型的注解
                        Constraints con = field.getAnnotation(Constraints.class);
                        columnName += buildConstraints(con);
    
                        // 否则检查是否包含 @SQLString 注解
                    }else if(annotation instanceof SQLString) {
                        SQLString sString = (SQLString) annotation;
                        if(sString.name().length() == 0) {
                            columnName = field.getName().toLowerCase();
                        }else{
                            // 如果没有设置name属性,就用字段名作为列名
                            columnName = sString.name();
                        }
                        // 获取字段长度属性
                        columnName += " VARCHAR(" + sString.value() + ")";
                        // 获取字段上的约束类型的注解
                        Constraints con = field.getAnnotation(Constraints.class);
                        columnName += buildConstraints(con);
                    }
                }
                columnNameList.add(columnName);
            }
    
    
            StringBuilder createConmmand = new StringBuilder("");
            createConmmand.append("CREATE TABLE ").append(tableName).append("(");
    
            int length = columnNameList.size();
            for (int i = 0; i < length; i ++) {
                createConmmand.append("\n    ").append(columnNameList.get(i));
                if(i != length -1){
                    createConmmand.append(",");
                }
            }
    
            createConmmand.append(");");
    
    
            return createConmmand.toString();
        }
    
        public String buildConstraints(Constraints con){
            if(con == null) {
                return "";
            }
            if(!con.allowNull()){
                return " NOT NULL";
            }
            if(con.primary()){
                return " PRIMARY KEY";
            }
            if(con.unique()) {
                return " UNIQUE";
            }
            return "";
        }
    }
    
    public class AnnotationDemo {
    
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> userClass = Class.forName("io.dc.User");
            String sql =  new TableCreator().createTableSQLString(userClass);
            // 直接下面的也行
    //        String sql =  new TableCreator().createTableSQLString(User.class);
            System.out.println(sql);
        }
    }
    
    • 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
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206

    结果:

    CREATE TABLE users(
        id INT NOT NULL,
        age INT,
        name VARCHAR(20));
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    allure测试报告应用和实践
    docker-compose Install rustdesk
    学完了Hadoop,我总结了这些重点
    算法的时间复杂度和空间复杂度
    视觉算法-软件-芯片-电驱技术
    如何使用ArcGIS Pro自动矢量化道路
    Java 时区
    C++学习概述
    离线数据仓库第二讲
    2020年12月大学英语六级作文(二)
  • 原文地址:https://blog.csdn.net/a141210104/article/details/127676273