目錄
- 内置的注解
-
- 作用在代碼的注解
- 元注解(或者說:作用在其他注解的注解)
- 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 架構
從上圖,我們可以看出:
-
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