注解的定义
注解(Annotation)和注释(Comment)一样都不是程序本身,而是对程序作出解释,而注解与注释不同的点在于,注解可以被其他程序,比如编译器读取。
注解的作用
- 生成 javadoc 文档;
- 跟踪代码依赖性,实现代替配置文件功能;
- 在编译时进行格式检查。
注解的分类
三个内置注解
@Override
:表示重写的注解;@Deprecated
:表示即将废弃的注解,可以用来修饰方法,属性,类;@SuperWarnings
:表示抑制警告信息的注解,在写代码时,可能会出现一些黄色的警告,但是并不影响运行,我们可以用这个注解来隐藏这些警告。与前两个注解不同的是我们必须给这个注解参数才能正确使用。参数如下:
参数 | 说明 |
---|---|
deprecation | 使用了过时的类或方法的警告 |
unchecked | 执行了未检查的转换时的警告 如:使用集合时未指定泛型 |
fallthrough | 当在 switch 语句使用时发生 case 穿透 |
serial | 当在序列化的类上缺少 serialVersionUID 定义时的警告 |
path | 在类路径、源文件路径中有不存在路径的警告 |
finally | 任何 finally 子句不能完成时的警告 |
all | 包括以上所有的警告 |
四个元注解
元注解的作用就是负责注解其它注解。
@Target
:用于表示注解的使用范围的元注解;其中的可选参数如下:
使用范围 | 取值 ElementType |
---|---|
包 | PACKAGE |
类、接口、枚举、注解 | TYPE |
类型成员 | FIELD:用于描述域;CONSTRUCTOR:用于描述构造器;METHOD:用于描述方法。 |
其它 | LOCAL_VARIABLE:用于描述局部变量;PARAMETER:用于描述参数。 |
@Retention
:用于描述注解的生命周期的元注解,作用是告诉编译器该注解信息的保存级别,其中的可选参数如下:
| 参数 | 取值 RetentionPolicy |
| :-----: | :------------------: |
| SOURCE | 在源代码中有效 |
| CLASS | 在类文件中有效 |
| RUNTIME | 在运行时有效 |
一般情况下我们使用 RUNTIME 参数,因为这样我们可以在程序运行时通过反射 机制来读取该注解。
@Document
:说明该注解将被包含在 javadoc 中;@Inherited
:说明子类可以继承父类中的该注解。
自定义注解
通过如下的代码,以及对应的注释可以很好的掌握自定义注解,同时注解的强大作用就需要之后和的反射一起结合起来看。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Test {
// 现学先用,直接使用下面自己创建的注解
// 多个参数使用 “,” 隔开
@CustomizeAnnotation(age = 24, schools = {"浙江工业大学", "兰溪市第三中学"})
public void method(){
System.out.println("That`s all.");
}
}
// 当然还可以用元注解修饰注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
/**
* 这是一个自定义的名为 CustomizeAnnotation 的注解
* 注解是用 @interface 修饰的:(public) @interface 注解名(定义内容)
* @author sharm
*/
@interface CustomizeAnnotation{
// 注解参数的形式为:参数类型 + 参数名();
// 若参数没有默认值,因此在使用时必须给定参数
int age();
// 若参数存在默认值,则在使用时可以不给定参数,而使用默认参数
String name() default "sharm";
// 参数类型只能是八大基本数据类型、String、Enum、Class、Annotation 以及它们对应的类型数组之一
String[] schools();
}
参考文献一:传送门
参考文献二:传送门
反射机制介绍
在运行期间,通过 Java 的反射机制,对于任何一个类,都能够知道这个类的属性和方法;对于任何一个对象,都能够调用这个对象的属性和方法。Java 的反射机制可以让用户动态地获取类的信息以及动态调用对象的功能。
反射的原理就是利用 Java 虚拟机通过类的字节码文件反向获取该类或者对象中的属性和方法。
反射机制优缺点
- 优点: 动态加载类,提高代码灵活度;
- **缺点:**因为反射相当于一系列解释操作,因此性能比直接的 java 代码要慢;使用反射会模糊程序内部逻辑。
反射的实现方式
Class 类是基于反射机制的,Class 由 final 修饰,一个 Class 类的实例表示这个类的类型信息。
- 通过
Class c1 = 类名.class
- 通过
Class c2 = 对象名.getClass()
- 通过
Class c3 = Class.forName(类的全名的字符串)
通过反射获取注解的信息
任务:利用注解和反射完成类和表结构的映射关系,即:
代码实现并运行,注意点在注释中:
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class ReflectAnnotation {
// 接下来可以通过反射得到对应的注解信息,以此来完成通过类得到数据库表中的信息
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
// 首先通过反射得到对应的 class 对象
Class person = Class.forName("Person");
// 1.通过反射获取类的全部注解信息
Annotation[] annotations = person.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 2.通过反射获取类的具体注解信息
ClassAnnotation classAnnotation = (ClassAnnotation)person.getAnnotation(ClassAnnotation.class);
System.out.println(classAnnotation.value());
//3.通过反射获得类中属性(域)的具体注解信息
// getDeclaredField 的是不包括从父类继承的注解
Field field = person.getDeclaredField("age");
FiledAnnotation filedAnnotation = field.getAnnotation(FiledAnnotation.class);
System.out.println(filedAnnotation.columnName());
System.out.println(filedAnnotation.type());
System.out.println(filedAnnotation.length());
}
}
// 该注解表明该对象对应的表名为 dataset_person
@ClassAnnotation(value = "dataset_person")
class Person{
// 域对应数据库表中的属性
@FiledAnnotation(columnName = "dataset_id", type = "int", length = 10)
int id;
@FiledAnnotation(columnName = "dataset_name", type = "varchar", length = 10)
String name;
@FiledAnnotation(columnName = "dataset_age", type = "int", length = 3)
int age;
public Person() {
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
// 对应类名(数据库表名)的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ClassAnnotation{
String value();
}
// 对应域(数据库字段)的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FiledAnnotation{
String columnName();
String type();
int length();
}