天天看點

Java注解(Annotation)内置的注解

目錄

  • 内置的注解
    • 作用在代碼的注解
    • 元注解(或者說:作用在其他注解的注解)
    • Annotation 架構
      • 說明
    • 元注解
    • Annotation 的作用

Java 注解(Annotation)又稱 Java 标注,是 JDK5.0 引入的一種注釋機制。

Java 語言中的類、方法、變量、參數和包等都可以被标注。和 Javadoc 不同,Java 标注可以通過反射擷取标注内容。在編譯器生成類檔案時,标注可以被嵌入到位元組碼中。Java 虛拟機可以保留标注内容,在運作時可以擷取到标注内容 。 當然它也支援自定義 Java 标注。

内置的注解

Java 定義了一套注解,共有 7 個,3 個在 java.lang 中,剩下 4 個在 java.lang.annotation 中(也稱為元注解)。

其中最重要的是元注解。元注解的作用就是負責注解其他注解。Java5.0定義了4個标準的meta-annotation類型,它們被用來提供對其它 annotation類型作說明。

作用在代碼的注解

  • @Override - 檢查該方法是否是重寫方法。如果發現其父類,或者是引用的接口中并沒有該方法時,會報編譯錯誤。
  • @Deprecated - 标記過時方法。如果使用該方法,會報編譯警告。
  • @SuppressWarnings - 訓示編譯器去忽略注解中聲明的警告。

元注解(或者說:作用在其他注解的注解)

  • @Target - 标記這個注解應該是哪種 Java 成員。
  • @Retention - 辨別這個注解怎麼儲存,是隻在代碼中,還是編入class檔案中,或者是在運作時可以通過反射通路。
  • @Documented - 标記這些注解是否包含在使用者文檔中。
  • @Inherited - 标記這個注解是繼承于哪個注解類(預設 注解并沒有繼承于任何子類)。

Annotation 架構

Java注解(Annotation)内置的注解

從上圖,我們可以看出:

  • 1 個 Annotation 和 1 個 RetentionPolicy 關聯。

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

  • 1 個 Annotation 和 1~n 個 ElementType 關聯。

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

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

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

說明

(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) SOURCE:在源檔案中有效(即源檔案保留)

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

b) CLASS:在class檔案中有效(即class保留)

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

c) RUNTIME:在運作時有效(即運作時保留)

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

元注解

@Target

@Target說明了Annotation所修飾的對象範圍:Annotation可被用于 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目标。

作用:用于描述注解的使用範圍(即:被描述的注解可以用在什麼地方)

取值(ElementType)有:

1.CONSTRUCTOR:用于描述構造器
 2.FIELD:用于描述域
 3.LOCAL_VARIABLE:用于描述局部變量
 4.METHOD:用于描述方法
 5.PACKAGE:用于描述包
 6.PARAMETER:用于描述參數
 7.TYPE:用于描述類、接口(包括注解類型) 或enum聲明
           
@Target(ElementType.TYPE)
public @interface Table {
    /**
     * 資料表名稱注解,預設值為類名稱
     * @return
     */
    public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {

}
           

@Retention

@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丢棄;而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛拟機忽略,而另一些在class被裝載時将被讀取(請注意并不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。

作用:表示需要在什麼級别儲存該注釋資訊,用于描述注解的生命周期(即:被描述的注解在什麼範圍内有效)

取值(RetentionPoicy)有:

1.SOURCE:在源檔案中有效(即源檔案保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在運作時有效(即運作時保留)
           

Retention meta-annotation類型有唯一的value作為成員,它的取值來自java.lang.annotation.RetentionPolicy的枚舉類型值。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}
           

@Documented

@Documented用于描述其它類型的annotation應該被作為被标注的程式成員的公共API,是以可以被例如javadoc此類的工具文檔化。Documented是一個标記注解,沒有成員。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}
           

@Inherited

@Inherited 元注解是一個标記注解,@Inherited闡述了某個被标注的類型是被繼承的。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個annotation将被用于該class的子類。

注意:@Inherited annotation類型是被标注過的class的子類所繼承。類并不從它所實作的接口繼承annotation,方法并不從它所重載的方法繼承annotation。

當@Inherited annotation類型标注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查将展開工作:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。

/**
 * 
 * @author peida
 *
 */
@Inherited
public @interface Greeting {
    public enum FontColor{ BULE,RED,GREEN};
    String name();
    FontColor fontColor() default FontColor.GREEN;
}
           

Annotation 的作用

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

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

1-編譯檢查

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

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

  • 關于@SuppressWarnings和@Deprecated,已經在“第3部分”中詳細介紹過了。這裡就不再舉例說明了。
  • 若某個方法被 @Override的 标注,則意味着該方法會覆寫父類中的同名方法。如果有方法被@Override标示,但父類中卻沒有“被@Override标注”的同名方法,則編譯器會報錯。

2-在反射中使用Annotation

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

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

3-根據Annotation生成幫助文檔

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

4-能夠幫忙檢視檢視代碼

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

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

聲明:本篇文章借鑒了以下兩篇寫的非常棒的文章。

https://www.runoob.com/w3cnote/java-annotation.html

https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html