注解还是很重要的,在这里先列举一些注解概述与基本的使用
注解一般在框架中是结合反射来使用的,可通过反射机制来读取注解,实现对元数据的访问
自定义注解的方式
使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口
public @interface MyAnnotation {
}
@interface 用来声明一个注解:格式: public @interface 注解名 { 定义内容 }
其中的每一个方法实际上是声明了一个配置参数
方法的名称就是参数的名称
返回值类型就是参数的类型(返回值只能是基本类型、Class 、String 、enum )
可以通过 default 来声明参数的默认值
如果只有一个参数成员,一般参数名为 value
注解元素必须要有值,我们定义注解元素时,常使用空字符串,0 作为默认值
@MyAnnotation1
public class AnnotationTest {
@MyAnnotation1
public void test1() {
}
@MyAnnotation2("aaa") // 可以把原先的 @MyAnnotation2(value = "aaa") 省略掉 value。默认规定
public void test2() {
}
}
@Inherited
@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation1 { // 使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口
String name() default ""; // 可以通过 default 来声明参数的默认值
int id() default -1; // 使用注解时,只要有一个属性没有默认赋值,则使用时就要去手动赋值,不然会报错
String[] schools() default {"清华大学", "北京大学"};
}
@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {
/**
* 只有一个注解的情况下,建议把参数名定义成 value,这样子使用时可以省略掉这个参数
* 如果参数不用 value 作为参数名
* 如用 name,则使用起来则需要:@MyAnnotation2(name = "aaa")
*/
String value();
}
元注解
Java 定义了 4 个标准的 meta-annotation 类型,被用来提供对其他 annotation 类型做说明
这些类型和他们所支持的类,在 java.lang.annotation 包中可以找到:@Target、@Retention、@Documented、@Inherited
-
@Target:用于描述注解的使用范围 -
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期SOURCE < CLASS < RUNTIME(框架都是 runtime,意思是注解要保证到了运行时还是可用的)
-
@Documented:说明该注解将被包含在 javadoc 中 -
@Inherited:说明子类可以继承父类的注解
通过反射来获取注解信息
这下面的代码看得不清楚,直接上截图可能就清晰一些了
然后在表对应的实体类使用这个注解,是不是就很有感觉,有一种在写 Mybatis 的感觉
然后框架底层通过反射,调用到我们实体类的注解上的信息,就取出信息对应到数据库自动连接执行操作
在这里我还没去研究过 Mybatis 源码,估计过阵子会去看看 Mybatis 的源码
在下面贴一个完整的测试代码,有需要的可以自行 copy 测试
public class Reflect05 {
public static void main(String[] args) throws NoSuchFieldException {
Class<Teacher> clazz = Teacher.class;
Class<? extends Teacher> zhangsan = new Teacher(1, "zhangsan", 30).getClass();
// 获取类上的注解(此时还没能获取 Field 上的注解)
TableChen annotation = clazz.getDeclaredAnnotation(TableChen.class);
System.out.println(annotation.value());
// 获取某个 Field 上的注解
Field field = zhangsan.getDeclaredField("name");
FieldChen fieldAnnotation = field.getDeclaredAnnotation(FieldChen.class);
System.out.println(fieldAnnotation.columnName());
}
}
// 假如有个 Teacher 表,那就要对应一个 Teacher 类
@TableChen("db_teacher")
class Teacher {
@FieldChen(columnName = "teacher_id", type = "bigint", length = 255)
private int id;
@FieldChen(columnName = "teacher_name", type = "varchar", length = 255)
private String name;
@FieldChen(columnName = "teacher_name", type = "int", length = 3)
private int age;
public Teacher() {}
public Teacher(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
/**
* 对应 ORM 框架的表
* Object Relationship Mapping(对象关系映射)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableChen {
String value(); // 表名
}
/**
* 对应 ORM 框架的字段
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldChen {
String columnName(); // 字段名
String type(); // 字段类型
int length(); // 字段长度
}