一、什么是注釋
說起注釋,得先提一提什么是元數據(metadata)。所謂元數據就是數據的數據。也就是說,元數據是描述數據的。就象數據表中的字段一樣,每個字段描述了這個字段下的數據的含義。而J2SE5.0中提供的注釋就是java源代碼的元數據,也就是說注釋是描述java源代碼的。在J2SE5.0中可以自定義注釋。使用時在@后面跟注釋的名字。
二、J2SE5.0中預定義的注釋
在J2SE5.0的java.lang包中預定義了三個注釋。它們是Override、Deprecated和SuppressWarnings。下面分別解釋它們的含義。
1. Override注釋:僅用於方法(不可用於類、包或其他),指明注釋的方法將覆蓋超類中的方法(如果覆蓋父類的方法而沒有注
釋就無法編譯該類),注釋還能確保注釋父類方法的拼寫是正確(錯誤的編寫,編譯器不認為是子類的新方法,而會報錯)
2. @Deprecated注釋:對不應再使用的方法進行注釋,與正在聲明為過時的方法放在同一行。使用被Deprecated注釋的方法,編譯器會
提示方法過時警告(”Warring”)
3. @SuppressWarnings注釋:單一注釋,可以通過數組提供變量,變量值指明要阻止的特定類型警告(忽略某些警告)。數組中的變量指明要阻止的警告@SuppressWarnings(value={”unchecked”, ”fallthrough”}))
三、自定義注釋@interface
@interface:注釋聲明,定義注釋類型(與默認的Override等三種注釋類型類似)。請看下面實例:
注釋類1(類注釋):
package a.test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FirstAnno { String value() default "FirstAnno"; }
注釋類2(方法注釋):
package a.test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SecondAnnotation { // 注釋中含有兩個參數 String name() default "Hrmzone"; String url() default "hrmzone.cn"; }
注釋類3(成員變量注釋):
package a.test; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Kitto { String value() default "kitto"; }
使用類:
package a.test; @FirstAnno("http://hrmzone.cn") public class Anno { @Kitto("測試") private String test = ""; // 不賦值注釋中的參數,使用默認參數 @SecondAnnotation() public String getDefault() { return "get default Annotation"; } @SecondAnnotation(name="desktophrm",url="desktophrm.com") public String getDefine() { return "get define Annotation"; } }
測試類:
package a.test; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class AnnoTest { public static void main(String[] args) throws ClassNotFoundException { // 要使用到反射中的相關內容 Class c = Class.forName("a.test.Anno"); Method[] method = c.getMethods(); boolean flag = c.isAnnotationPresent(FirstAnno.class); if (flag) { FirstAnno first = (FirstAnno) c.getAnnotation(FirstAnno.class); System.out.println("First Annotation:" + first.value() + "\n"); } List<Method> list = new ArrayList<Method>(); for (int i = 0; i < method.length; i++) { list.add(method[i]); } for (Method m : list) { SecondAnnotation anno = m.getAnnotation(SecondAnnotation.class); if (anno == null) continue; System.out.println("second annotation's\nname:\t" + anno.name() + "\nurl:\t" + anno.url()); } List<Field> fieldList = new ArrayList<Field>(); for (Field f : c.getDeclaredFields()) {// 訪問所有字段 Kitto k = f.getAnnotation(Kitto.class); System.out.println("----kitto anno: " + k.value()); } } }
結合源文件中注釋,想必對注釋的應用有所了解。下面深入了解。
@Target:指定程序元定義的注釋所使用的地方,它使用了另一個類:ElementType,是一個枚舉類定義了注釋類型可以應用到不同的程序元素以免使用者誤用。看看java.lang.annotation 下的源代碼:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[]value(); }
ElementType是一個枚舉類型,指明注釋可以使用的地方,看看ElementType類:
public enum ElementType { TYPE, // 指定適用點為 class, interface, enum FIELD, // 指定適用點為 field METHOD, // 指定適用點為 method PARAMETER, // 指定適用點為 method 的 parameter CONSTRUCTOR, // 指定適用點為 constructor LOCAL_VARIABLE, // 指定使用點為 局部變量 ANNOTATION_TYPE, // 指定適用點為 annotation 類型 PACKAGE // 指定適用點為 package }
@Retention:這個元注釋和java編譯器處理注釋的注釋類型方式相關,告訴編譯器在處理自定義注釋類型的幾種不同的選擇,需要使用RetentionPolicy枚舉類。此枚舉類只有一個成員變量,可以不用指明成名名稱而賦值,看Retention的源代碼:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
類中有個RetentionPolicy類,也是一個枚舉類,具體看代碼:
public enum RetentionPolicy { SOURCE, // 編譯器處理完Annotation后不存儲在class中 CLASS, // 編譯器把Annotation存儲在class中,這是默認值 RUNTIME // 編譯器把Annotation存儲在class中,可以由虛擬機讀取,反射需要 }
@Documented:是一個標記注釋,表示注釋應該出現在類的javadoc中,因為在默認情況下注釋時不包括在javadoc中的。 所以如果花費了大量的時間定義一個注釋類型,並想描述注釋類型的作用,可以使用它。
注意他與@Retention(RetentionPolicy.RUNTIME)配合使用,因為只有將注釋保留在編譯后的類文件中由虛擬機加載, 然后javadoc才能將其抽取出來添加至javadoc中。
@Inherited:將注釋同樣繼承至使用了該注釋類型的方法中(表達有點問題,就是如果一個方法使用了的注釋用了@inherited,那么其子類的該方法同樣繼承了該注釋)
注意事項:
1. 所有的Annotation自動繼承java.lang.annotation接口
2. 自定義注釋的成員變量訪問類型只能是public、default;(所有的都能訪問,源作者沒用到函數:getDeclaredFields而已)
3. 成員變量的只能使用基本類型(byte、short、int、char、long、double、float、boolean和String、Enum、Class、annotations以及該類型的數據)(沒有限制,大家可以修改測試一下,就清楚)
4. 如果只有一個成員變量,最好將參數名稱設為value,賦值時不用制定名稱而直接賦值
5. 在實際應用中,還可以使用注釋讀取和設置Bean中的變量。