面試必備——Java的Annotation註解

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 提供了用於處理類型和聲明的一些工具。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章