Java 語言特性之 Annotation 註解
利用 Java 的反射機制,可以在執行時獲取 Java 類的註解資訊。
註解
註解的特性
註解是 Java 5 的一個新特性,是插入程式碼中的一種註釋或者說是元資料。註解並不是程式程式碼,可以對程式作出解釋,類似於註釋。但是註解可以被相關程式讀取(例如編譯器)。
註解可以用在兩個時刻:
- 在編譯期間,編譯工具會對註解進行處理
- 在執行期間,使用 Java 反射機制進行處理
註解格式及用法
註解的格式:註解以 @
開頭,後面跟註釋名,還可以加引數。
註解使用的地方:package,class,method,field 上都可以使用註解。
- 類註解:
@MyAnnotation(name="someName", value = "Hello World")
public class TheClass {
}
- 方法註解:
@Override
public String toString() { // 這裡如果方法名寫錯,會報錯
return "";
}
註解的定義
註解的定義與介面的定義相似,但是需要在 interface 關鍵字前加 @
符號:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
元註解 meta-annotation
元註解負責註解其他註解。Java 定義了4個標準的元註解型別,用來對其它 註解型別作說明:
@Target
@Target
用於描述註解的使用位置。例如 @Target(ElementType.TYPE)
表示這個註解只能用在型別上面(比如類跟介面)。引數可以同時指定多個值,例如@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
- CONSTRUCTOR:用於構造器
- FIELD:用於欄位
- LOCAL_VARIABLE:用於區域性變數
- METHOD:用於方法
- PACKAGE:用於包
- PARAMETER:用於引數
- TYPE:用於類、介面(包括註解型別) 或enum宣告
@Retention
@Retention
用於描述註解的生命週期。可取值有:
- SOURCE:在原始檔中有效,編譯時丟棄
- CLASS:在class檔案中有效,執行時丟棄
- RUNTIME:在執行時有效
@Documented
@Documented
用於描述是否可以被 javadoc 之類的工具文件化。@Documented
是標記註解,沒有成員。
@Inherited
@Inherited
用於描述某個被標註的型別是被繼承的。如果一個使用了 @Inherited
修飾的annotation型別被用於一個class,則這個註解將被用於該class的子類。
當@Inherited 型別標註的註解的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用 java.lang.reflect 反射機制去查詢一個@Inherited 型別的註解時,反射程式碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation型別被發現,或者到達類繼承結構的頂層。
內建註解
@Override
定義在 java.lang.Override
中,此註解只能用於修飾方法,表示重寫父類中的方法。
@Deprecated
定義在 java.lang.Deprecated
中,可以用於修飾方法、屬性或類,表示方法、屬性或類已經廢棄,不建議使用。
@SuppressWarnings
定義在 java.lang.SuppressWarnings
中,抑制編譯時的警告資訊。可以指定以下的一個或多個引數,例如 `@SuppressWarngins(value={“unchecked”, “path”}):
- all:抑制所有警告
- deprecate:抑制廢棄方式、屬性或類的警告
- unchecked:抑制未檢查的警告,例如使用集合時未指定泛型
- path:路徑、檔案不存在的警告
- finally:抑制 finally 子句不能完成時的警告
自定義註解
使用 @interface
自定義註解時,自動繼承 java.lang.annotation.Annotation
介面。註解不能繼承其他的註解或介面。
@interface
用來宣告一個註解,其中的每一個方法實際上是聲明瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別(返回值型別只能是基本資料型別(int,float,boolean,byte,double,char,long,short)、Class、String、enum 及這些型別對應的陣列)。可以通過default來宣告引數的預設值。
定義註解的語法:
public @interface 註解名 {定義體}
- 例如,註解使用:
@MyAnnotation(name="someName", value = "Hello World")
public class TheClass {
}
- 註解定義:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String value();
}
訪問註解
只要是 Runtime 級別的註解,不管是類、方法、引數、變數註解都可以在執行時通過反射機制載入類後,進行訪問,具體方法可以參考 這裡。
Class aClass = TheClass.class;
Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}