天天看點

Java 注解@Annotation 與 自定義注解

1.注解的由來

在引入注解之前,在不同類型的應用程式使用XML作為标準的代碼配置機制,程式員們描述其代碼的形式尚未标準化,每個人的做法各異:transient關鍵字、注釋、接口等,代碼和XML的解耦以及未來對這種解耦應用的維護并不低廉,這顯然不是一種優雅的方式,随之而來的JDK5.0引入一種嶄新的記錄中繼資料的形式——注解被引入到Java中。 它的作用是修飾程式設計元素。什麼是程式設計元素呢?例如:包、類、構造方法、方法、成員變量等。

2.什麼是注解

DK5.0中的類型:1、類(class)2、接口(interface)3、枚舉(enum)4、注解(Annotation) 是以,注解與其他3種類型一樣,都可以定義、使用,以及包含有自己的屬性、方法

注解分類 :

  • 标記注釋:注解的内部沒有屬性,稱作标記注解 使用方法:@注解名 使用例子:@MarkAnnotation。
  • 單值注解:注解的内部隻有一個屬性,稱作單值注解 使用方法:@注解名(屬性名=屬性值) 使用例子:@SingleAnnotation(value="abc") //也可以寫成@SingleAnnotation("abc") *(屬性名=屬性值)可以簡化為(屬性值),但是需要滿足以下兩個條件: 1、該注解必須為單值注解 2、該注解的屬性名必須為value。
  • 多值注解:注解的内部有多個屬性,稱作多值注解 使用方法:@注解名(屬性名1=屬性值1, 屬性名2=屬性值2……) 使用例子:@MultipliedAnnotation(value1 = "abc", value2 = 30……)。

元注解 

Java提供了一下幾個元注解:Target、Retention、Documented和Inherited。

元注解的作用:

可以用于注解類(annotate Classes)、注解接口(annotate Interfaces)、注解枚舉類型(annotate Enums) 也可以用于注解注解(annotate Annotations)。

3.注解文法

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

java.lang.annotation.Annotation :

public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}
           

java.lang.annotation.ElementType :

public enum ElementType {
    TYPE,               /* 類、接口(包括注釋類型)或枚舉聲明  */

    FIELD,              /* 字段聲明(包括枚舉常量)  */

    METHOD,             /* 方法聲明  */

    PARAMETER,          /* 參數聲明  */

    CONSTRUCTOR,        /* 構造方法聲明  */

    LOCAL_VARIABLE,     /* 局部變量聲明  */

    ANNOTATION_TYPE,    /* 注釋類型聲明  */

    PACKAGE             /* 包聲明  */
}
           

java.lang.annotation.RetentionPolicy : 

public enum RetentionPolicy {
    SOURCE,            /* Annotation資訊僅存在于編譯器處理期間,編譯器處理完之後就沒有該Annotation資訊了  */

    CLASS,             /* 編譯器将Annotation存儲于類對應的.class檔案中。預設行為  */

    RUNTIME            /* 編譯器将Annotation存儲于class檔案中,并且可由JVM讀入 */
}
           

各自作用:

  • Annotation就是一個接口,"每 1 個 Annotation" 都與 "1 個 RetentionPolicy" 關聯,并且與 "1~n 個 ElementType" 關聯。可以通俗的了解為:每 1 個 Annotation 對象,都會有唯一的 RetentionPolicy 屬性;至于 ElementType 屬性,則有 1~n 個。
  • ElementType是Enum枚舉類型,用來指定Annotation的作用範圍。當 Annotation 與某個 ElementType 關聯時,就意味着:Annotation有了某種作用範圍。例如,若一個 Annotation 對象是 METHOD 類型,則該 Annotation 能用來修飾方法。
  • RetentionPolicy 是 Enum 枚舉類型,它用來指定 Annotation 的政策。通俗點說,就是不同 RetentionPolicy 類型的 Annotation 的作用域不同。"每 1 個 Annotation" 都與 "1 個 RetentionPolicy" 關聯。

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

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

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

4.内置注解

Java 5 定義了一套注解,共有 7 個,3 個在 java.lang 中,剩下 4 個在 java.lang.annotation 中。

作用在代碼的注解是:

  • @Override - 檢查該方法是否是重載方法。如果發現其父類,或者是引用的接口中并沒有該方法時,會報編譯錯誤。
  • @Deprecated - 标記過時方法。在源程式中加入這個标記後,并不影響程式的編譯,但編譯器會顯示一些警告資訊。
  • @SuppressWarnings - 用于有選擇的關閉編譯器對類、方法、成員變量、變量初始化的警告:
    deprecation:使用了不贊成使用的類或方法時的警告;
    unchecked:執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合儲存的類型; 
    fallthrough:當 Switch 程式塊直接通往下一種情況而沒有 Break 時的警告;
    path:在類路徑、源檔案路徑等中有不存在的路徑時的警告; 
    serial:當在可序列化的類上缺少 serialVersionUID 定義時的警告; 
    finally:任何 finally 子句不能正常完成時的警告; 
    all:關于以上所有情況的警告。
               

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

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

從 Java 7 開始,額外添加了 3 個注解:

  • @SafeVarargs - Java 7 開始支援,忽略任何使用參數為泛型變量的方法或構造函數調用産生的警告。
  • @FunctionalInterface - Java 8 開始支援,辨別一個匿名函數或函數式接口。
  • @Repeatable - Java 8 開始支援,辨別某注解可以在同一個聲明上使用多次。

5.自定義注解

用一個例子來說明:

@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PerformanceLog {
    String value() default "";
}
           

說明:

上面的作用是定義一個 Annotation,它的名字是 PerformanceLog。定義了 PerformanceLog 之後,我們可以在代碼中通過 "@PerformanceLog" 來使用它。 其它的,@Documented, @Target, @Retention, @interface 都是來修飾 PerformanceLog 的。下面分别說說它們的含義:

  • @interface:

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

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

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

  • @Documented:

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

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

  • @Target(ElementType.TYPE)

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

    @Target({ElementType.METHOD, ElementType.TYPE})的意思就是指定該 Annotation 的類型是 ElementType.METHOD, ElementType.TYPE。這就意味着,PerformanceLog 是來修飾"方法、類、接口(包括注釋類型)或枚舉聲明"的注解。

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

  • @Retention(RetentionPolicy.RUNTIME)
    前面我們說過,RetentionPolicy 是 Annotation 的政策屬性,而 @Retention 的作用,就是指定 Annotation 的政策屬性。@Retention(RetentionPolicy.RUNTIME) 的意思就是指定該 Annotation 的政策是 RetentionPolicy.RUNTIME。這就意味着,編譯器會将該 Annotation 資訊保留在 .class 檔案中,并且能被虛拟機讀取。定義 Annotation 時,@Retention 可有可無。若沒有 @Retention,則預設是 RetentionPolicy.CLASS。