一、什么是注解
注解(Annontation)是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。注解(Annontation)像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
二、注解的用处
1、生成文档。
2、跟踪代码依赖性,实现替代配置文件功能。
3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
三、注解的原理
注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。
四、JDK自带注解
@Override,表示当前的方法定义将覆盖超类中的方法。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated,表示该方法已经过时了。使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnings,关闭不当编译器警告信息。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
五、元注解
元注解是由java提供的基础注解,负责注解其它注解,如上面的 Override被@Target和@Retention修饰,它们用来说明解释其它注解,位于sdk/sources/android-25/java/lang/annotation路径下。
元注解有:
@Retention:注解保留的生命周期。
@Target:注解对象的作用范围。
@Inherited:@Inherited标明所修饰的注解,在所作用的类上,是否可以被继承。
@Documented:如其名,javadoc的工具文档化,一般不关心。
@Target:Target标明了注解的适用范围,对应ElementType枚举,明确了注解的有效范围。可能的ElementType参数有:
TYPE:类、接口、枚举、注解类型。
FIELD:类成员(构造方法、方法、成员变量)。
METHOD:方法。
PARAMETER:参数。
CONSTRUCTOR:构造器。
LOCAL_VARIABLE:局部变量。
ANNOTATION_TYPE:注解。
PACKAGE:包声明。
TYPE_PARAMETER:类型参数。
TYPE_USE:类型使用声明。
@Retention:Retention说标明了注解被生命周期,对应RetentionPolicy的枚举,表示注解在何时生效:
SOURCE:只在源码中有效,编译时抛弃,如上面的@Override。
CLASS:编译class文件时生效。
RUNTIME:运行时才生效。
@Inherited:注解所作用的类,在继承时默认无法继承父类的注解。除非注解声明了 @Inherited。同时Inherited声明出来的注解,只对类有效,对方法/属性无效。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
@Documented:一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。
六、自定义注解
自定义注解类编写的一些规则:
1、 Annotation型定义为@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口。
2、参数成员只能用public或默认(default)这两个访问权修饰。
3、 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组。
4、要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象,因为你除此之外没有别的获取注解对象的方法。
下面通过一个简单的对象关系映射(ORM)程序来学习一下自定义注解(Object Relational Mapping)。
一、定义两个注解类
MyTable
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTable {
String value();
}
MyField
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyField {
String column();
String type();
}
二、在User类上使用注解
@MyTable(value = "tbl_user")
public class User {
@MyField(column = "id", type = "int")
private int id;
@MyField(column = "age", type = "int")
private int age;
@MyField(column = "name", type = "varchar")
private String name;
public User() {
}
public User(int id, int age, String name) {
super();
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
三、利用反射读取解析注解
public class Annocation {
public static void main(String[] args) {
String path = "com.cczhang.annocation.User";
try {
Class<User> clazz = (Class<User>) Class.forName(path);
// User user = clazz.newInstance();
//获取类的所有有效注解
Annotation[] annocations = clazz.getAnnotations();
for (Annotation a:annocations) {
System.out.println(a);
}
//获取类的指定的注解
MyTable table = clazz.getAnnotation(MyTable.class);
System.out.println(table.value());
//获取类的属性的注解
Field field = clazz.getDeclaredField("name");
MyField myField = field.getAnnotation(MyField.class);
System.out.println(myField.column()+"--"+myField.type());
System.out.println("所有属性:");
Field[] fields = clazz.getDeclaredFields();
for (Field f :fields) {
MyField mf = f.getAnnotation(MyField.class);
System.out.println(mf.column()+"--"+mf.type());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@com.cczhang.annocation.MyTable(value=tbl_user)
tbl_user
name--varchar
所有属性:
id--int
age--int
name--varchar
四、根据获得的表名,字段的信息拼出DDL语句,然后使用JDBC执行这个SQL,在数据库中生成相关的表
DDL(Data Definition Language),数据库模式定义语言,是用于描述数据库中要存储的现实世界实体的语言。