Annotation(注解)是从JDK5.0开始引入的新技术。Annotation的主要作用:
- 不属于程序本身,但是可以对程序作出解释。
- 可以被其他程序(例如:编译器等)读取。
Annotation注解以“@注释名”在代码中存在的,还可以添加一些参数值,例如@SuppressWarnings(value = “unchecked”)。Annotation可以附加在package、class、method、field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。
一.注解
1.1内置注解
内置注解主要有@Override、@Deprecated和@SuppressWarnings。这里主要说一下@SuppressWarning,@SuppressWarning主要用来抑制编译时的告警信息。我们在使用@SuppressWarning的时候,需要添加一个参数才能正确的使用,这些参数主要如下:
参数 | 说明 |
deprecation | 使用了过时的类或方法的告警 |
unchecked | 执行了未检查的转换时的告警,如使用集合时未指定泛型 |
fallthroungh | 当在switch语句时发生case穿透 |
path | 在类路径、源文件路径等中有不存在路径的告警 |
serial | 当在可序列化的类上缺少serialVersionUID定义时的告警 |
finally | 任何finally子句不能完成时的警告 |
all | 关于以上所有情况的告警 |
1.2自定义注解
我们可以自己定义注解,格式如下:
- public @interface 注解名{定义体},使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
- 其中的每一个方法实际上是声明了一个配置参数。
- 方法的名称就是参数的名称。
- 方法的返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String和enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value。使用的时候,我们可以不指定名称。
注解元素在使用的时候必须要有赋值,但是我们在定义注解元素时,可以设置默认值,例如经常使用空字符串、0作为默认值,也经常使用负数(比如-1)表示不存在的含义。注解如果仅仅只是定义,而实际上没有通过反射等进行解析,实际上是没有任何的意义的。
1.3元注解
元注解(meta-annotation)是指注解的注解,包括@Retention @Target @Document @Inherited四种。
1.3.1@Target
@Target用于描述注解的使用范围,例如@Target(value=ElementType.TYPE)。
所修饰的范围 | 取值ElementType |
package 包 | PACKAGE |
类、接口、枚举、Annotation类型 | Type |
类型成员(方法、构造方法、成员变量、枚举值) | CONSTRUCTOR:用于描述构造器 FIELD:用于描述域 METHOD:用于描述方法 |
方法参数和本地变量 | LOCAL_VARIABLE:用于描述局部变量 PARAMETER:用于参数 |
@Retention
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期。
取值RetentionPolicy | 作用 |
SOURCE | 在源文件中有效(即源文件保留) |
CLASS | 在class文件中有效(即class保留) |
RUNTIME | 在运行时有效(即运行时保留),为Runtime可以被反射机制读取 |
二.例子
使用注解完成以下类和表结构的映射关系:
表结构如下:
CREATE TABLE `tb_student`(
`id` int(10) not null auto_increment,
`sname` varchar(10) default null,
`age` int(3) default null,
primary key(`id`)
)engine=InnoDB default charset=utf8
类的结构定义如下:
public class Student {
private int id;
private String studentName;
private int age;
}
完成类和表的映射关系,主要需要做以下三件事情:
- 类和表结构的对应
- 属性和字段的对应
- 对象和记录的对应
首先定义表注解Table:
@Target(value={ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
定义字段注解:
@Target(value={ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String columnName();
String type();
int length();
}
定义对象和记录的注解:
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Record {
String studentName() default "";
int age() default 0;
int id() default -1;
}
定义完注解对象之后,类Student使用注解完成映射:
@Table("tb_student")
public class Student {
@Field(columnName="id",type="int",length=10)
private int id;
@Field(columnName="sname",type="varchar",length=10)
private String studentName;
@Field(columnName="age",type="int",length=3)
private int age;
}
定义测试类Demo,使用注解@Record:
public class Demo {
@Record(age=19,studentName="王五",id=1001)
public void test(){
}
}
定义测试类Demo2,使用反射获取注解对象并做处理:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 使用反射读取注解的信息,模拟处理注解信息的流程
* @author 尚学堂高淇
*
*/
public class Demo02 {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.bjsxt.test.annotation.SxtStudent");
//获得类的所有有效注解
Annotation[] annotations=clazz.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
//获得类的指定的注解
Table st = (Table) clazz.getAnnotation(Table.class);
System.out.println(st.value());
//获得类的属性的注解
Field f = clazz.getDeclaredField("studentName");
Column column = f.getAnnotation(Column.class);
System.out.println(column.columnName()+"--"+column.type()+"--"+column.length());
//根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表
} catch (Exception e) {
e.printStackTrace();
}
}
}