天天看點

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

摘要

Java Annotation是JDK5.0引入的一種注釋機制。

網上很多關于Java Annotation的文章,看得人眼花缭亂。Java Annotation本來很簡單的,結果說的人沒說清楚;弄的看的人更加迷糊。

我按照自己的思路,對Annotation進行了整理。了解 Annotation 的關鍵,是了解Annotation的文法和用法,對這些内容,我都進行了詳細說明;了解Annotation的文法和用法之後,再看Annotation的架構圖,可能有更深刻體會。廢話就說這麼多,下面開始對Annotation進行說明。若您發現文章中存在錯誤或不足的地方,希望您能指出!

第1部分 Annotation架構

先看看Annotation的架構圖:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

從中,我們可以看出:

(01) 1個Annotation 和 1個RetentionPolicy關聯。

       可以了解為:每1個Annotation對象,都會有唯一的RetentionPolicy屬性。

(02) 1個Annotation 和 1~n個ElementType關聯。

       可以了解為:對于每1個Annotation對象,可以有若幹個ElementType屬性。

(03) Annotation 有許多實作類,包括:Deprecated, Documented, Inherited, Override等等。

       Annotation 的每一個實作類,都“和1個RetentionPolicy關聯”并且“和1~n個ElementType關聯”。

下面,我先介紹架構圖的左半邊(如下圖),即Annotation, RetentionPolicy, ElementType;然後在就Annotation的實作類進行舉例說明。

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

第2部分 Annotation組成部分

1 annotation組成成分

java annotation 的組成中,有3個非常重要的主幹類。它們分别是:

(01) Annotation.java

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

(02) ElementType.java

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

(03) RetentionPolicy.java

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

說明:

(01) Annotation 就是個接口。

    “每1個Annotation” 都與 “1個RetentionPolicy”關聯,并且與

“1~n個ElementType”關聯。可以通俗的了解為:每1個Annotation對象,都會有唯一的RetentionPolicy屬性;至于

ElementType屬性,則有1~n個。

(02) ElementType 是Enum枚舉類型,它用來指定Annotation的類型。

      “每1個Annotation” 都與 “1~n個ElementType”關聯。當Annotation與某個ElementType關聯時,就意味着:Annotation有了某種用途。

      例如,若一個Annotation對象是METHOD類型,則該Annotation隻能用來修飾方法。

(03) RetentionPolicy 是Enum枚舉類型,它用來指定Annotation的政策。通俗點說,就是不同RetentionPolicy類型的Annotation的作用域不同。

      “每1個Annotation” 都與 “1個RetentionPolicy”關聯。

      a) 若Annotation的類型為 SOURCE,則意味着:Annotation僅存在于編譯器處理期間,編譯器處理完之後,該Annotation就沒用了。

          例如,“ @Override ”标志就是一個Annotation。當它修飾一個方法的時候,就意味着該方法覆寫父類的方法;并且在編譯期間會進行文法檢查!編譯器處理完後,“@Override”就沒有任何作用了。

      b) 若Annotation的類型為 CLASS,則意味着:編譯器将Annotation存儲于類對應的.class檔案中,它是Annotation的預設行為。

      c) 若Annotation的類型為 RUNTIME,則意味着:編譯器将Annotation存儲于class檔案中,并且可由JVM讀入。

這時,隻需要記住“每1個Annotation” 都與 “1個RetentionPolicy”關聯,并且與 “1~n個ElementType”關聯。學完後面的内容之後,再回頭看這些内容,會更容易了解。

第3部分 java自帶的Annotation

了解了上面的3個類的作用之後,我們接下來可以講解Annotation實作類的文法定義了。

上面的作用是定義一個Annotation,它的名字是MyAnnotation1。定義了MyAnnotation1之後,我們可以在代碼中通過“@MyAnnotation1”來使用它。

其它的,@Documented, @Target, @Retention, @interface都是來修飾MyAnnotation1的。下面分别說說它們的含義:

(01) @interface

       使用@interface定義注解時,意味着它實作了java.lang.annotation.Annotation接口,即該注解就是一個Annotation。

       定義Annotation時,@interface是必須的。

       注意:它和我們通常的implemented實作接口的方法不同。Annotation接口的實作細節都由編譯器完成。通過@interface定義注解後,該注解不能繼承其他的注解或接口。

(02) @Documented

       類和方法的Annotation在預設情況下是不出現在javadoc中的。如果使用@Documented修飾該Annotation,則表示它可以出現在javadoc中。

       定義Annotation時,@Documented可有可無;若沒有定義,則Annotation不會出現在javadoc中。

(03) @Target(ElementType.TYPE)

      前面我們說過,ElementType 是Annotation的類型屬性。而@Target的作用,就是來指定Annotation的類型屬性。

      @Target(ElementType.TYPE) 的意思就是指定該Annotation的類型是ElementType.TYPE。這就意味着,MyAnnotation1是來修飾“類、接口(包括注釋類型)或枚舉聲明”的注解。

      定義Annotation時,@Target可有可無。若有@Target,則該Annotation隻能用于它所指定的地方;若沒有@Target,則該Annotation可以用于任何地方。

(04) @Retention(RetentionPolicy.RUNTIME)

      前面我們說過,RetentionPolicy 是Annotation的政策屬性,而@Retention的作用,就是指定Annotation的政策屬性。

    @Retention(RetentionPolicy.RUNTIME)

的意思就是指定該Annotation的政策是RetentionPolicy.RUNTIME。這就意味着,編譯器會将該Annotation資訊保留

在.class檔案中,并且能被虛拟機讀取。

      定義Annotation時,@Retention可有可無。若沒有@Retention,則預設是RetentionPolicy.CLASS。

2 java自帶的Annotation

通過上面的示例,我們能了解:@interface用來聲明Annotation,@Documented用來表示該Annotation是否會出現在javadoc中, @Target用來指定Annotation的類型,@Retention用來指定Annotation的政策。

了解這一點之後,我們就很容易了解java中自帶的Annotation的實作類,即Annotation架構圖的右半邊。如下圖:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

java 常用的Annotation:

由于“@Deprecated和@Override”類似,“@Documented, @Inherited, @Retention, @Target”類似;下面,我們隻對@Deprecated, @Inherited, @SuppressWarnings 這3個Annotation進行說明。

2.1 @Deprecated

@Deprecated 的定義如下:

(01) @interface -- 它的用來修飾Deprecated,意味着Deprecated實作了java.lang.annotation.Annotation接口;即Deprecated就是一個注解。

(02) @Documented -- 它的作用是說明該注解能出現在javadoc中。

(03)

@Retention(RetentionPolicy.RUNTIME) --

它的作用是指定Deprecated的政策是RetentionPolicy.RUNTIME。這就意味着,編譯器會将Deprecated的資訊保留

(04) @Deprecated 所标注内容,不再被建議使用。

       例如,若某個方法被 @Deprecated 标注,則該方法不再被建議使用。如果有開發人員試圖使用或重寫被@Deprecated标示的方法,編譯器會給相應的提示資訊。示例如下:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

源碼如下(DeprecatedTest.java):

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

View Code

上面是eclipse中的截圖,比較類中 “getString1() 和 getString2()” 以及 “testDate() 和 testCalendar()” 。

(01) getString1() 被@Deprecated标注,意味着建議不再使用getString1();是以getString1()的定義和調用時,都會一橫線。這一橫線是eclipse()對@Deprecated方法的處理。

       getString2() 沒有被@Deprecated标注,它的顯示正常。

(02) testDate() 調用了Date的相關方法,而java已經建議不再使用Date操作日期/時間。是以,在調用Date的API時,會産生警告資訊,途中的warnings。

       testCalendar() 調用了Calendar的API來操作日期/時間,java建議用Calendar取代Date。是以,操作Calendar不回産生warning。

2.2 @Inherited

@Inherited 的定義如下:

(01) @interface -- 它的用來修飾Inherited,意味着Inherited實作了java.lang.annotation.Annotation接口;即Inherited就是一個注解。

@Retention(RetentionPolicy.RUNTIME) --

它的作用是指定Inherited的政策是RetentionPolicy.RUNTIME。這就意味着,編譯器會将Inherited的資訊保留

(04) @Target(ElementType.ANNOTATION_TYPE) -- 它的作用是指定Inherited的類型是ANNOTATION_TYPE。這就意味着,@Inherited隻能被用來标注“Annotation類型”。

(05) @Inherited 的含義是,它所标注的Annotation将具有繼承性。

 假設,我們定義了某個Annotaion,它的名稱是MyAnnotation,并且MyAnnotation被标注為@Inherited。現在,某

個類Base使用了MyAnnotation,則Base具有了“具有了注解MyAnnotation”;現在,Sub繼承了Base,由于

MyAnnotation是@Inherited的(具有繼承性),是以,Sub也“具有了注解MyAnnotation”。

@Inherited的使用示例

源碼如下(InheritableSon.java):

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

運作結果:

InheritableFather:true

InheritableSon:true

現在,我們對InheritableSon.java進行修改:注釋掉“Inheritable的@Inherited注解”。

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

InheritableSon:false

對比上面的兩個結果,我們發現:當注解Inheritable被@Inherited标注時,它具有繼承性。否則,沒有繼承性。

2.3 @SuppressWarnings

@SuppressWarnings 的定義如下:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

(01) @interface -- 它的用來修飾SuppressWarnings,意味着SuppressWarnings實作了java.lang.annotation.Annotation接口;即SuppressWarnings就是一個注解。

(02)

@Retention(RetentionPolicy.SOURCE) --

它的作用是指定SuppressWarnings的政策是RetentionPolicy.SOURCE。這就意味着,SuppressWarnings

資訊僅存在于編譯器處理期間,編譯器處理完之後SuppressWarnings就沒有作用了。

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})

-- 它的作用是指定SuppressWarnings的類型同時包括TYPE, FIELD, METHOD, PARAMETER,

CONSTRUCTOR, LOCAL_VARIABLE。

       TYPE意味着,它能标注“類、接口(包括注釋類型)或枚舉聲明”。

       FIELD意味着,它能标注“字段聲明”。

       METHOD意味着,它能标注“方法”。

       PARAMETER意味着,它能标注“參數”。

       CONSTRUCTOR意味着,它能标注“構造方法”。

       LOCAL_VARIABLE意味着,它能标注“局部變量”。

(04) String[] value(); 意味着,SuppressWarnings能指定參數

(05)

SuppressWarnings

的作用是,讓編譯器對“它所标注的内容”的某些警告保持靜默。例如,"@SuppressWarnings(value={"deprecation",

"unchecked"})" 表示對“它所标注的内容”中的

“SuppressWarnings不再建議使用警告”和“未檢查的轉換時的警告”保持沉默。示例如下:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

源碼如下(SuppressWarningTest.java):

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

(01) 左邊的圖中,沒有使用 @SuppressWarnings(value={"deprecation"}) , 而Date屬于java不再建議使用的類。是以,調用Date的API時,會産生警告。

      而右邊的途中,使用了 @SuppressWarnings(value={"deprecation"})。是以,編譯器對“調用Date的API産生的警告”保持沉默。

補充:SuppressWarnings 常用的關鍵字的表格

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

第4部分 Annotation 的作用

Annotation 是一個輔助類,它在Junit、Struts、Spring等工具架構中被廣泛使用。

我們在程式設計中經常會使用到的Annotation作用有:

1 編譯檢查

Annotation具有“讓編譯器進行編譯檢查的作用”。

例如,@SuppressWarnings, @Deprecated和@Override都具有編譯檢查作用。

(01) 關于@SuppressWarnings和@Deprecated,已經在“第3部分”中詳細介紹過了。這裡就不再舉例說明了。

(02) 若某個方法被 @Override的 标注,則意味着該方法會覆寫父類中的同名方法。如果有方法被@Override标示,但父類中卻沒有“被@Override标注”的同名方法,則編譯器會報錯。示例如下:

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

源碼(OverrideTest.java):

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

上面是該程式在eclipse中的截圖。從中,我們可以發現“getString()”函數會報錯。這是因為“getString() 被@Override所标注,但在OverrideTest的任何父類中都沒有定義getString1()函數”。

“将getString() 上面的@Override注釋掉”,即可解決該錯誤。

2 在反射中使用Annotation

在反射的Class, Method, Field等函數中,有許多于Annotation相關的接口。

這也意味着,我們可以在反射中解析并使用Annotation。

源碼如下(AnnotationTest.java):

Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義
Java Annotation認知(包括架構圖、詳細介紹、示例說明)1 Annotation通用定義

somebody: lily, 18

girl, boy,

@com.skywang.annotation.MyAnnotation(value=[girl, boy])

empty

unknown,

@com.skywang.annotation.MyAnnotation(value=[unknown])

@java.lang.Deprecated()

3 根據Annotation生成幫助文檔

通過給Annotation注解加上@Documented标簽,能使該Annotation标簽出現在javadoc中。

4 能夠幫忙檢視檢視代碼

通過@Override, @Deprecated等,我們能很友善的了解程式的大緻結構。

另外,我們也可以通過自定義Annotation來實作一些功能。

繼續閱讀