Annotation
Annotation是一個接口,程序可以通過反射來獲取指定程序元素的Annotation對象,然後通過Annotation對象來取得註釋裏的元數據。
Annotation必須使用工具來處理,工具負責提取Annotation裏包含的元數據,工具還會根據這些元數據增加額外的功能。使用Annotation時要在其前面增加@符號,並把該Annotation當成一個修飾符使用。
限定重寫父類方法:@Override
@Override就是用來指定方法覆載的,它可以強制一個子類必須要覆蓋父類的方法。只能作用於方法。
標示已過時:@Deprecated
@Deprecated用來表示某個程序元素已過時,當其他程序使用已過時的類、方法時,編譯器便會給出警告。
抑制編譯器警告:@SuppressWarnings
@SuppressWarnings指示被Annotation標識的程序元素取消顯示指定的編譯器警告。@SuppressWarnings會一直作用於該程序元素的所有子元素。
自定義Annotation
定義新的Annotation類型使用interface關鍵字,它用於定義一個新的Annotation類型。定義一個新的Annotation類型與定義一個接口非常像,如:
//定義一個簡單的Annotation類型
public @interface Test{}
定義了該Annotation之後,就可以在程序任何地方來使用該Annotation,使用Annotation時的語法類似於public、final等修飾符。通常將其放在所有修飾符之前。
Annotation還可以帶成員變量:
public @interface MyTag{
//定義了兩個成員變量的Annotation
//Annotation中的成員變量以方法的形式來定義
String name();
int age();
}
一旦在Annotation裏定義了成員變量之後,使用該Annotation時應該爲該Annotation的成員變量指定值:
public class Test{
//使用帶成員變量的Annotation時,需要爲成員變量賦值
@Mytag(name="xx",age=6)
public void info(){}
}
在定義Annotation的成員變量時爲其指定初始值,指定成員變量的初始值可使用default關鍵字。
public @interface MyTag{
//定義了兩個成員變量的Annotation
//Annotation中的成員變量以方法的形式來定義
String name() default "yeeku";
int age() default 32;
}
Annotation分爲兩類:
- 標記Annotation:一個沒有成員定義的Annotation類型被稱爲標記。這種Annotation僅使用自身的存在與否來爲我們提供信息。
- 元數據Annotation:那些包含成員變量的Annotation,因爲它們可接受更多元數據。
提取Annotation的信息
Java使用Annotation接口來代表程序元素前面的註釋,該接口是所有Annotation類型的父接口。除此之外,Java在java.lang.reflect包下新增了AnnotatedElement接口,該接口代表程序中可以接受註釋的程序元素,該接口主要有如下幾個實現類:
- Class:類定義
- Constructor:構造器定義
- Field:類的成員變量定義
- Method:類的方法定義
- Package:類的包定義
java.lang.reflect包下主要包含一些實現反射功能工具類,實際上,java.lang.reflect包所提供的反射API擴充了讀取運行時Annotation的能力。當一個Annotation類型被定義爲運行時Annotation後,該註釋纔是運行時可見,當class文件被裝載時被保存在class文件中的Annotation纔會被虛擬機讀取。
AnnotatedElement接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取某個類的AnnotatedElement對象之後,程序就可以調用方法訪問Annotation信息:
- getAnnotation(Class annotationClass):返回該程序元素上存在的、指定類型的註釋,如果該類型的註釋不存在,則返回null。
- Annotation[] getAnnotations():返回該程序元素上存在的所有註釋。
- boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的註釋,存在則返回true,否則返回false。
JDK的元Annotation
java.lang.annotation包下提供了四個Meta Annotation,這四個Annotation都是用於修飾其他Annotation定義。
使用@Retention
@Retention只能用於修飾一個Annotation定義,用於指定該Annotation可以保留多長時間,@Retention包含一個RetentionPolicy類型的value成員變量,所以使用@Retention時必須爲該value成員變量指定值。
value成員變量的值只能是下列三個:
- RetentionPolicy.Class:編譯器將把註釋記錄在class文件中。當運行Java程序時,JVM不再保留註釋。這是默認值。
- RetentionPolicy.RUNTIME:編譯器將把註釋記錄在class文件中。當運行Java程序時,JVM也會保留註釋,程序可以通過反射獲取該註釋。
- RetentionPolicy.SOURCE:編譯器直接丟棄這種策略的註釋。
使用@Documented
@Documented用於指定被該元Annotation修飾的Annotation類將被javadoc工具提取成文檔。
使用@Inherited
@Inherited元Annotation指定被他修飾的Annotation將具有繼承性:如果某個類使用了A的Annotation(定義該Annotation時使用了@Inherited修飾)修飾,則其子類將自動具有A註釋。
使用APT處理Annotation
APT是一種處理Annotation的工具,它對源代碼文件進行檢測找出其中的Annotation後,使用Annotation進行額外的處理。
Annotation處理器在處理Annotation時可以根據源文件中的Annotation生成額外的源文件和其他文件,APT還會編譯生成的源代碼文件和原來的源文件將它們一起生成class文件。
爲了使用系統的APT工具來讀取源文件中的Annotation,程序員必須自定義一個Annotation處理器,編寫Annotation處理器需要使用JDK lib目錄中的tools.jar裏的四個包:
- com.sun.mirror.apt:和APT交互的接口
- com.sun.mirror.declaration:包含各種封裝類成員、類方法、類聲明的接口。
- com.sun.mirror.type 包含各種封裝源代碼中程序元素的接口。
- com.sun.mirror.util 提供了用於處理類型和聲明的一些工具。