Annotation簡介
Annotation是JDK1.5引入的特性,包含在java.lang.annotation包中。
它是附加在代碼中的一些元信息,將一個類的外部信息與內(nèi)部成員聯(lián)系起來,在 編譯、運行時進行解析和使用(可以理解成Python的裝飾器)。
Java內(nèi)置了一些Annotation(例如 @Override、@Deprecated等),也支持用戶定義自己的Annotation,像Hibernate、Spring等框架都大量的自定義了Annotation。
什么是Annotation?
用一個詞就可以描述Annotation —— "元數(shù)據(jù)",一種描述“數(shù)據(jù)”的“數(shù)據(jù)”;可以說Annotation就是源代碼的“元數(shù)據(jù)”。
@Override
public String toString() {
return "Annotation Demo";
}
上面的代碼中重寫了 toString()方法,并使用了@Override Annotation。該Annotation表示什么?有什么用處?實際上@Override會告訴編譯器這個方法是一個重寫方法,如果父類中不存在該方法,編譯器就會報錯。
Annotation是一種應用與 類、接口、方法、參數(shù)、變量、構(gòu)造器及包聲明中的特殊修飾符,詳細內(nèi)容可以查看枚舉ElementType。
為什么要引入Annotation?
在Annotation出現(xiàn)之前,XML被廣泛應用關(guān)于描述元數(shù)據(jù),但是程序員和架構(gòu)師發(fā)現(xiàn)XML的維護越來越麻煩,他們希望使用一些和代碼緊耦合的東西,而不是想XML那樣和代碼是松耦合的,最有趣的是XML配置實際上是為了分離代碼和配置而引入的。
假如你想為應用設(shè)置很多常量或參數(shù),XML是一個很好的選擇,因為它不會和特定的代碼相連。如果你想把某個Method聲明為服務(wù),那么使用Annotation會更簡單、方便一些,因為這種情況下需要Annotation和Method緊密耦合起來。
目前需要框架將XML和Annotation兩種方式都結(jié)合使用,平衡兩者之間的利弊。
Annotation是如何工作的?
先來看看@Override的代碼
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
對于@Override你肯定會有疑問,它的內(nèi)部什么都沒做,它是如何檢查父類中有沒有同名的方法呢?@Override的定義不僅僅只有這么一點代碼(注意:Annotation僅僅是元數(shù)據(jù),和業(yè)務(wù)邏輯無關(guān)),那@Override到底是如何實現(xiàn)的呢? 答:AnnotationProcessor
Annotation示例代碼:https://docs.google.com/file/d/0B1N2DVZFnNU0dVdFVjVFeTVtcXc/edit
AnnotationProcessor
是一個在javac中的,用來編譯時掃描和處理的Annotation的工具。一個Annotation的AnnotationProcessor,以Java代碼(或者編譯過的字節(jié)碼)作為輸入,生成文件(通常是.java文件)作為輸出。這具體的含義什么呢?你可以生成Java代碼!
生成的Java代碼是在新的.java文件中,所以你并不能修改已存在的Java類,例如向已有的類中添加方法。并且這些生成的Java文件,會同其他普通的手動編寫的Java源代碼一樣被javac編譯。
元注解
用來標注其它注解而創(chuàng)建的新注解,元注解的類型有以下幾種:
@Target:注解所修飾的對象范圍
@Inherited:表示注解可以被繼承
@Documented:表示這個注解應該被JavaDoc工具記錄
@Rentation:用來聲明注解的保留策略
@Repeable:JDK8新增,允許一個注解在同一聲明類型(類,屬性或方法)上多次使用。
自定義Annotation
那么,注解的內(nèi)部到底是如何定義的呢?Annotations只支持基本類型、String及枚舉類型。注釋中所有的屬性被定義成方法,并允許提供默認值。
示例代碼:
01、MyTag類
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
String name() default "Car";
int size() default 10;
}
02、Car實體類
public class Car {
private String name;
private int size;
public Car(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Car(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", size=" + size +
'}';
}
}
03、AnnotationDemo
public class AnnotationDemo {
@MyTag(name = "Audi", size = 100) // 裝配Car這個類
private Car car;
public Car getCar(){
return car;
}
public void setCar(Car car){
this.car = car;
}
@Override
public String toString() {
return "AnnotationDemo{" +
"car=" + car +
'}';
}
}
04、AnnotationProcessor
import java.lang.reflect.Field;
public class AnnotationProcessor {
public static void annotationProcess(AnnotationDemo annotationDemo){
for(Field field: annotationDemo.getClass().getDeclaredFields()){
if(field.isAnnotationPresent(MyTag.class)){ // 如果存在MyTag標簽
MyTag myTag = field.getAnnotation(MyTag.class);
annotationDemo.setCar(new Car(myTag.name(), myTag.size()));
}
}
}
public static void main(String[] args){
AnnotationDemo annotationDemo = new AnnotationDemo();
annotationProcess(annotationDemo);
System.out.println(annotationDemo.getCar());
}
}