JDK5.0中提供了註解的功能,容許開發者定義和使用本身的註解類型。該功能由一個定義註解類型的語法和描述一個註解聲明的語法,讀取註解的API,一個使用註解修飾的class文件和一個註解處理工具組成。html
Annotation並不直接影響代碼的語義,可是他能夠被看作是程序的工具或者類庫。它會反過來對正在運行的程序語義有所影響。java
Annotation能夠衝源文件、class文件或者在運行時經過反射機制多種方式被讀取。程序員
java.lang
註釋類型 Override
@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override
表示一個方法聲明打算重寫超類中的另外一個方法聲明。若是方法利用此註釋類型進行註解但沒有重寫超類方法,則編譯器會生成一條錯誤消息。數組
@Override註解表示子類要重寫父類的對應方法。ide
Override是一個Marker annotation,用於標識的Annotation,Annotation名稱自己表示了要給工具程序的信息。工具
下面是一個使用@Override註解的例子:this
class A { private String id; A(String id){ this.id = id; } @Override public String toString() { return id; } }
java.lang
註釋類型 Deprecated
@Documented
@Retention(value=RUNTIME)
public @interface Deprecated
用 @Deprecated 註釋的程序元素,不鼓勵程序員使用這樣的元素,一般是由於它很危險或存在更好的選擇。在使用不被同意的程序元素或在不被同意的代碼中執行重寫時,編譯器會發出警告。spa
@Deprecated註解表示方法是不被建議使用的。設計
Deprecated是一個Marker annotation。code
下面是一個使用@Deprecated註解的例子:
class A { private String id; A(String id){ this.id = id; } @Deprecated public void execute(){ System.out.println(id); } public static void main(String[] args) { A a = new A("a123"); a.execute(); } }
java.lang 註釋類型 SuppressWarnings @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings
指示應該在註釋元素(以及包含在該註釋元素中的全部程序元素)中取消顯示指定的編譯器警告。注意,在給定元素中取消顯示的警告集是全部包含元素中取消顯示的警告的超集。例如,若是註釋一個類來取消顯示某個警告,同時註釋一個方法來取消顯示另外一個警告,那麼將在此方法中同時取消顯示這兩個警告。
根據風格不一樣,程序員應該始終在最裏層的嵌套元素上使用此註釋,在那裏使用纔有效。若是要在特定的方法中取消顯示某個警告,則應該註釋該方法而不是註釋它的類。
@SuppressWarnings註解表示抑制警告。
下面是一個使用@SuppressWarnings註解的例子:
@SuppressWarnings("unchecked") public static void main(String[] args) { List list = new ArrayList(); list.add("abc"); }
使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其餘細節。在定義註解時,不能繼承其餘的註解或接口。
自定義最簡單的註解:
public @interface MyAnnotation { }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation public void execute(){ System.out.println("method"); } }
public @interface MyAnnotation { String value1(); }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation(value1="abc") public void execute(){ System.out.println("method"); } }
當註解中使用的屬性名爲value時,對其賦值時能夠不指定屬性的名稱而直接寫上屬性值接口;除了value意外的變量名都須要使用name=value的方式賦值。
public @interface MyAnnotation { String value1() default "abc"; }
public @interface MyAnnotation { String value1() default "abc"; MyEnum value2() default MyEnum.Sunny; } enum MyEnum{ Sunny,Rainy }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation(value1="a", value2=MyEnum.Sunny) public void execute(){ System.out.println("method"); } }
public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) public void execute(){ System.out.println("method"); } }
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Retention
指示註釋類型的註釋要保留多久。若是註釋類型聲明中不存在 Retention 註釋,則保留策略默認爲 RetentionPolicy.CLASS。
只有元註釋類型直接用於註釋時,Target 元註釋纔有效。若是元註釋類型用做另外一種註釋類型的成員,則無效。
public enum RetentionPolicy extends Enum<RetentionPolicy>
註釋保留策略。此枚舉類型的常量描述保留註釋的不一樣策略。它們與 Retention 元註釋類型一塊兒使用,以指定保留多長的註釋。
CLASS
編譯器將把註釋記錄在類文件中,但在運行時 VM 不須要保留註釋。
RUNTIME
編譯器將把註釋記錄在類文件中,在運行時 VM 將保留註釋,所以能夠反射性地讀取。
SOURCE
編譯器要丟棄的註釋。
@Retention註解能夠在定義註解時爲編譯程序提供註解的保留策略。
屬於CLASS保留策略的註解有@SuppressWarnings,該註解信息不會存儲於.class文件。
@Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String[] value1() default "abc"; }
java.lang.reflect
接口 AnnotatedElement
全部已知實現類:
AccessibleObject, Class, Constructor, Field, Method, Package
表示目前正在此 VM 中運行的程序的一個已註釋元素。該接口容許反射性地讀取註釋。由此接口中的方法返回的全部註釋都是不可變而且可序列化的。調用者能夠修改已賦值數組枚舉成員的訪問器返回的數組;這不會對其餘調用者返回的數組產生任何影響。
若是此接口中的方法返回的註釋(直接或間接地)包含一個已賦值的 Class 成員,該成員引用了一個在此 VM 中不可訪問的類,則試圖經過在返回的註釋上調用相關的類返回的方法來讀取該類,將致使一個 TypeNotPresentException。
isAnnotationPresent boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
若是指定類型的註釋存在於此元素上,則返回 true,不然返回 false。此方法主要是爲了便於訪問標記註釋而設計的。
參數:
annotationClass - 對應於註釋類型的 Class 對象
返回:
若是指定註釋類型的註釋存在於此對象上,則返回 true,不然返回 false
拋出:
NullPointerException - 若是給定的註釋類爲 null
從如下版本開始:
1.5
getAnnotation <T extends Annotation> T getAnnotation(Class<T> annotationClass)
若是存在該元素的指定類型的註釋,則返回這些註釋,不然返回 null。
參數:
annotationClass - 對應於註釋類型的 Class 對象
返回:
若是該元素的指定註釋類型的註釋存在於此對象上,則返回這些註釋,不然返回 null
拋出:
NullPointerException - 若是給定的註釋類爲 null
從如下版本開始:
1.5
getAnnotations
Annotation[] getAnnotations()
返回此元素上存在的全部註釋。(若是此元素沒有註釋,則返回長度爲零的數組。)該方法的調用者能夠隨意修改返回的數組;這不會對其餘調用者返回的數組產生任何影響。
返回:
此元素上存在的全部註釋
從如下版本開始:
1.5
getDeclaredAnnotations
Annotation[] getDeclaredAnnotations()
返回直接存在於此元素上的全部註釋。與此接口中的其餘方法不一樣,該方法將忽略繼承的註釋。(若是沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)該方法的調用者能夠隨意修改返回的數組;這不會對其餘調用者返回的數組產生任何影響。
返回:
直接存在於此元素上的全部註釋
從如下版本開始:
1.5
下面是使用反射讀取RUNTIME保留策略的Annotation信息的例子:
自定義註解:
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) @Deprecated public void execute(){ System.out.println("method"); } }
讀取註解中的信息:
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { AnnotationTest2 annotationTest2 = new AnnotationTest2(); //獲取AnnotationTest2的Class實例 Class<AnnotationTest2> c = AnnotationTest2.class; //獲取須要處理的方法Method實例 Method method = c.getMethod("execute", new Class[]{}); //判斷該方法是否包含MyAnnotation註解 if(method.isAnnotationPresent(MyAnnotation.class)){ //獲取該方法的MyAnnotation註解實例 MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); //執行該方法 method.invoke(annotationTest2, new Object[]{}); //獲取myAnnotation String[] value1 = myAnnotation.value1(); System.out.println(value1[0]); } //獲取方法上的全部註解 Annotation[] annotations = method.getAnnotations(); for(Annotation annotation : annotations){ System.out.println(annotation); } }
限定註解使用@Target。
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Target
指示註釋類型所適用的程序元素的種類。若是註釋類型聲明中不存在 Target 元註釋,則聲明的類型能夠用在任一程序元素上。若是存在這樣的元註釋,則編譯器強制實施指定的使用限制。 例如,此元註釋指示該聲明類型是其自身,即元註釋類型。它只能用在註釋類型聲明上:
@Target(ElementType.ANNOTATION_TYPE) public @interface MetaAnnotationType { ... }
此元註釋指示該聲明類型只可做爲複雜註釋類型聲明中的成員類型使用。它不能直接用於註釋:
@Target({}) public @interface MemberType { ... }
這是一個編譯時錯誤,它代表一個 ElementType 常量在 Target 註釋中出現了不僅一次。例如,如下元註釋是非法的:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD}) public @interface Bogus { ... } public enum ElementType extends Enum<ElementType>
程序元素類型。此枚舉類型的常量提供了 Java 程序中聲明的元素的簡單分類。
這些常量與 Target 元註釋類型一塊兒使用,以指定在什麼狀況下使用註釋類型是合法的。
ANNOTATION_TYPE
註釋類型聲明
CONSTRUCTOR
構造方法聲明
FIELD
字段聲明(包括枚舉常量)
LOCAL_VARIABLE
局部變量聲明
METHOD
方法聲明
PACKAGE
包聲明
PARAMETER
參數聲明
TYPE
類、接口(包括註釋類型)或枚舉聲明
註解的使用限定的例子:
@Target(ElementType.METHOD) public @interface MyAnnotation { String[] value1() default "abc"; }
要想在製做JavaDoc文件的同時將註解信息加入到API文件中,可使用java.lang.annotation.Documented。
在自定義註解中聲明構建註解文檔:
@Documented public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義註解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) public void execute(){ System.out.println("method"); } }
默認狀況下註解並不會被繼承到子類中,能夠在自定義註解時加上java.lang.annotation.Inherited註解聲明使用繼承。
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Inherited
指示註釋類型被自動繼承。若是在註釋類型聲明中存在 Inherited 元註釋,而且用戶在某一類聲明中查詢該註釋類型,同時該類聲明中沒有此類型的註釋,則將在該類的超類中自動查詢該註釋類型。此過程會重複進行,直到找到此類型的註釋或到達了該類層次結構的頂層 (Object) 爲止。若是沒有超類具備該類型的註釋,則查詢將指示當前類沒有這樣的註釋。
注意,若是使用註釋類型註釋類之外的任何事物,此元註釋類型都是無效的。還要注意,此元註釋僅促成從超類繼承註釋;對已實現接口的註釋無效。
本文轉自:http://www.itzhai.com/java-based-notebook-annotation-annotation-introduction-and-use-custom-annotations.html