1. 注解是什么
注解可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为类/方法注解不同的参数,在用到的地方可以得到不同的类/方法中注解的各种参数与值。从
JDK5
开始,java增加了对元数据(描述数据属性的信息)的支持。其实说白就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。
2. Java中默认提供的注解
- @Override
该注解表示该类覆盖了父类的方法,该注解只表示修饰,表示自雷想要重写父类的方法,如果使用该注解但没有重写父类的方法,会生成一条错误信息.
- @SuppressWarnings
该注解表示关闭一些警告信息,用来取消在编译时的一些警告信息,该注解必须添加参数才能使用,参数是JDK已经预先好的,我们只需选择对应的参数即可.
- @Deprecated
该注解表示方法已经过时,我们在使用带有该注解的方法时,方法会添加删除线,表示该方法已经过时不建议使用.
3. 自定义注解
1.自定义注解的语法规则
注解类使用@interface关键字修饰
成员以无参数无异常的方式声明,注意区别与普通成员变量的定义
可以通过default关键字来定义默认值
成员类型是受限的,合法的类型包括原始类型以及String、Class、Annotation、Enumeration (JAVA的基本数据类型有8种:byte(字节)、short(短整型)、int(整数型)、long(长整型)、float(单精度浮点数类型)、double(双精度浮点数类型)、char(字符类型)、boolean(布尔类型)
注解类可以没有成员,没有成员的注解称为标识注解,例如JDK注解中的@Override、@Deprecation
如果注解只有一个成员,并且把成员取名为value(),则在使用时可以忽略成员名和赋值号“=” ,例如JDK注解的@SuppviseWarnings ;如果成员名 不为value,则使用时需指明成员名和赋值号"=",
- 元注解
元注解就是给自定义的注解添加注解,你自己定义了一个注解,但你想要你的注解有什么样的功能,此时就需要用元注解对你的注解进行说明。Java5.0定义了4个标准的meta-annotation(元注解)类型,它们被用来提供对其它 annotation类型作说明。
- @Target
用来表示自定义注解的使用范围即注解可以使用在什么地方,如使用于类、方法、包等。
其取值在java.lang.annotation.ElementType中做了如下规定:
CONSTRUCTOR
:用于构造函数声明FIELD
:用于字段声明(包括枚举常量)LOCAL_VARIABLE
:用于局部变量声明METHOD
:用于方法声明PACKAGE
:用于包声明PARAMETER
:用于形式参数声明TYPE
:用于类,接口(包括注释类型)或枚举声明- ANNOTATION_TYPE:注解类型声明
- TYPE_PARAMETER:类型参数声明(JDK1.8)
- TYPE_USE:使用类型(JDK1.8)
- @Retention
用来表示注解作用域,即该注解合适被丢弃,JDK通过RetentionPolicy枚举类定义了以下几种作用域:
- SOURCE:注解将被编译器丢弃(即该注解只在源码中保留,在编译器进行编译时被丢弃)
- CLASS:注释将由编译器记录在类文件中,但不会在运行时由JVM保留。这是默认的行为
- RUNTIME:注释由编译器记录在类文件中,并在运行时由JVM保留,因此可以通过反射方式读取它们。
- @Documented
该注解没有成员,表示默认情况下,javadoc 和类似工具将记录带有类型的注释。此类型应用于注释类型的声明,这些声明的注释会影响其客户端对带注释的元素的使用。如果类型声明用有文档注释,则其注释将成为带注释元素的公共API的一部分。
- @Inherited
指示自动继承注释类型。如果@Inherited元注解在于注解类型上声明,用户查询类上的注释类型声明,而类声明没有此类型的注解,然后类的超类将自动查询注解类型。这个过程将会重复,直到有注解为止,或者达到了类层次结构(对象)的顶部。如果没有超类有此类型的注解,则表明所讨论的类没有这样的注解。请注意,如果带注解的类型用于注解类之外的任何内容,则此元注解类型无效。另请注意,此元注释仅使注解从超类继承;已实现的接口上的注释无效。
- 自定义注解
注解往往要和反射一起使用采用实际意义
如下是一个模拟Hibernate通过注解生成建表SQL的案例
新建注解类Table
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String tableName(); }
新建注解类Column
/** * @author XuDabin */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String value(); String type(); int length() default 10; String COMMENT() default ""; }
新建POJO(User.java),并通过自定义注解来标识类和字段
/** * @author XuDabin * @description * @create 2020-07-10 9:55 */ @Table(tableName = "user") public class User implements Serializable { @Column(value = "id", type = "int", COMMENT = "主键") private Long id; @Column(value = "username", type = "varchar", length = 20, COMMENT = "用户名") private String name; @Column(value = "password", type = "varchar", length = 30, COMMENT = "密码") private String password; }
新建测试类,通过反射来生成建表SQL
/** * @author XuDabin * @description * @create 2020-07-10 10:00 */ public class Demo { public static void main(String[] args) { String sql = getSql(); System.out.println(sql); } public static String getSql() { Class<ReUser> reUserClass = ReUser.class; StringBuffer sb = new StringBuffer("create table "); Class<User> userClass = User.class; Table table = userClass.getAnnotation(Table.class); sb.append(table.tableName() + "(\n"); Field[] fields = userClass.getDeclaredFields(); if (fields.length > 0) { for (Field f : fields) { if (f.isAnnotationPresent(Column.class)) { Column column = f.getAnnotation(Column.class); sb.append("\t" + column.value() + " "); sb.append(column.type() + "(" + column.length() + ") "); sb.append("COMMENT '" + column.COMMENT() + "',"); } } sb.deleteCharAt(sb.length() - 1); } sb.append("\n)"); return sb.toString(); } }
运行测试类能够获取到SQL
将SQL复制到Navicat中,新建查询并运行生成的SQL
成功通过生成的SQL创建表