欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

注解的学习以及使用

程序员文章站 2022-03-14 19:21:44
...

说明

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

内置的注解

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。

作用在其他注解的注解(元注解)是:
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

@Retention 表示需要在什么级别保存保存该注解信息
SOURCE 注解将被编译器丢丢弃
CLASS 注解在class文件中可用,但会被VM丢弃
RUNTIME VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
@Documented 将此注解包含在javadoc中
@Target 表示该注解可以用于什么地。ElementType参数包括
CONSTRUCTOR 构造器的说明
FIFLD 域说明
LOCAL_VARIABLE 局部变量说明
METHOD 方法说明
PACKAGE 包声明
PARAMETER 参数说明
TYPE 类,接口(包括注解类型)或enum声明
@Inherited 允许子类继承父类的注解

OK,说完基本的注解使用,我们可以做个小demo,加深对注解的理解。

Demo内容:

创建一个Bean类引用自己创建的注解,然后使用jdbc读取注解的sql,在进行创建

Demo做法如下,将创建下列注解:

@DBTable – 生成一个数据库表
@Constraints --此注解包含主键,是否为空,唯一索引
@SQLString --定义SQL类型
@SQLInteger --定义SQL类型

接下来,定义一个简单的bean类,实现以上注解

Member

最后,实现注解处理器类以及jdbc工具类

TableCreator – 注解处理类
DBUtil – jdbc工具类

代码如下:
@DBTable

package com.qing.annotations.database;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @program: Learn_Qing
 * @description 此注解是为告诉注解处理器,需要为此注解生成一个数据库表:
 * @author: Marven
 * @date: 2020-03-21 21:20
 **/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
    public String name() default "";
}

@Constraints

package com.qing.annotations.database;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @program: Learn_Qing
 * @description 修饰JavaBean域做准备:
 * @author: Marven
 * @date: 2020-03-21 21:25
 **/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
    boolean primaryKey() default false;
    boolean allowNull() default true;
    boolean unique() default false;
}

@SQLString

package com.qing.annotations.database;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @program: Learn_Qing
 * @description:
 * @author: Marven
 * @date: 2020-03-21 21:28
 **/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    int value() default 0;
    String name() default "";
    Constraints constraints() default @Constraints;
}

@SQLInteger

package com.qing.annotations.database;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @program: Learn_Qing
 * @description:
 * @author: Marven
 * @date: 2020-03-21 21:31
 **/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
    String name() default "";
    Constraints constraints() default @Constraints;
}

Member

package com.qing.annotations.database;

/**
 * @program: Learn_Qing
 * @description 注意,此域中每个注解都内嵌了@Constraints注解:
 * @author: Marven
 * @date: 2020-03-21 21:37
 **/
@DBTable(name = "MEMBER")//数据库将会创建名称为"MEMBER"表
public class Member {
    @SQLString(30) //数据库会将表的长度的设成30
    String firstName;
    @SQLString(50)
    String lastName;
    @SQLInteger
    Integer age;
    @SQLString(value = 30,constraints = @Constraints(primaryKey = true))//将handle列指定为主键
    String handle;
    static int memberCount;

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Integer getAge() {
        return age;
    }

    public String getHandle() {
        return handle;
    }

    public static int getMemberCount() {
        return memberCount;
    }
}

DBUtil

package com.qing.annotations.database.util;
import java.sql.*;
/**
 * @program: Learn_Qing
 * @description:
 * @author: Marven
 * @date: 2020-03-22 12:16
 **/
public class DBUtil
{
    /**
     * 注意,加载此驱动需要用到mavenJar包为
     * 		<dependency>
     * 			<groupId>mysql</groupId>
     * 			<artifactId>mysql-connector-java</artifactId>
     * 			<version>8.0.15</version>
     * 		</dependency>
     */
    private static String driver = "com.mysql.cj.jdbc.Driver";   //用于加载驱动
    private static String url = "jdbc:mysql://192.168.213.136/mall?characterEncoding=utf-8";  //数据库地址
    private static String username = "root";  //用户名
    private static String password = "root";   //密码

    //连接数据库
    public static Connection open()
    {
        try
        {
            Class.forName(driver);    //加载驱动
            return DriverManager.getConnection(url, username, password);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    //关闭数据库
    public static void close(Connection conn)
    {
        if(conn!=null)
        {
            try
            {
                conn.close();
            } catch (SQLException e)
            {
                e.printStackTrace();
            }
        }
    }
}

TableCreator

package com.qing.annotations.database;

import com.qing.annotations.database.util.DBUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: Learn_Qing
 * @description:
 * @author: Marven
 * @date: 2020-03-21 22:52
 **/
public class TableCreator {
    public static void main(String[] args) throws ClassNotFoundException {
        String sql = "";
        if(args.length < 1){
            System.out.println("参数: 带注解的类");
            System.exit(0);
        }
        for (String className : args){
            Class<?> cl = Class.forName(className);
            DBTable dbTable = cl.getAnnotation(DBTable.class);//getAnnotation方法返回该元素的指定类型的注解,如果是这样的注解,否则返回null。
            if(dbTable == null){
                System.out.println("没有 DATable 这个注解类 " + className);
                continue;
            }
            String tableName = dbTable.name();
            // 如果名称为空,请使用类名称
            if(tableName.length()<1)
                tableName = cl.getName().toUpperCase();
            List<String> columnDefs = new ArrayList<String>();
            //getDeclaredFields()获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
            for (Field field : cl.getDeclaredFields()){
                String columnName = null;
                Annotation[] anns = field.getDeclaredAnnotations();
                if(anns.length<1)
                    continue;
                if(anns[0] instanceof SQLInteger){
                    SQLInteger sINT = (SQLInteger) anns[0];

                    if(sINT.name().length()<1)
                        columnName = field.getName().toUpperCase();
                    else
                        columnName = sINT.name();
                    columnDefs.add(columnName + " INT " + getConstraints(sINT.constraints()));
                }
                if(anns[0] instanceof SQLString){
                    SQLString sString = (SQLString) anns[0];
                    if(sString.name().length() < 1)
                        columnName = field.getName().toUpperCase();
                    else
                        columnName = sString.name();
                    columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")"
                    + getConstraints(sString.constraints()));
                }
                StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
                for (String columnDef : columnDefs)
                    createCommand.append("\n     " + columnDef + ",");
                    //Remove trailing comma
                    String tableCreate = createCommand.substring(0,createCommand.length()-1) + ");";
                    System.out.println("sql创建表 " + className + " 是 :\n" + tableCreate);
                    sql = tableCreate;
            }
            //使用jdbc创建数据库表
            Connection conn = DBUtil.open();  //连接数据库
            try
            {
                Statement stmt = conn.createStatement();  //静态操作sql语句
                stmt.execute(sql);
                System.out.println("创建表成功");
            } catch (SQLException e)
            {
                e.printStackTrace();
            }
            finally
            {
                DBUtil.close(conn);
            }
        }
    }
    private static String getConstraints(Constraints con){
        String constraints = "";
        if(!con.allowNull())
            constraints += " NOT NULL";
        if(con.primaryKey())
            constraints += " PRIMARY KEY";
        if(con.unique())
            constraints += " UNIQUE";
        return constraints;
    }
}

温馨提示:

运行TableCreator类需要做一下设置:
直接图片说明,简单明了
注解的学习以及使用
接下来需要将Member类写到Program arguments中:
注解的学习以及使用
ok,点击右下角OK,在点击运行
注解的学习以及使用
下一步,我们可以到数据库中查询这张表是否存在
SQL: SHOW COLUMNS FROM MEMBER;
注解的学习以及使用

结果如下:
注解的学习以及使用

总结:

通过上面的展示的一个小Demo,可以使大家有所了解,老子有言:“上士闻道,勤而行之”,希望大家都能举一反三,如果能在实践中激发灵感,那是最好不过!

相关标签: 注解