java的注解處理器類主要是AnnotatedElement接口的實現類實現,為位於java.lang.reflect包下。由下面的class源碼可知AnnotatedElement接口是所有元素的父接口,這時我們通過反射獲得一個類的AnnotatedElement對象后,就可以通過下面表格的幾個方法,訪問Annotation信息。
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement{ }
java.lang.Class中有關getDeclared**和get**的方法以getDeclaredMethods和getMethods為例說明:
getDeclaredMethod(s):返回自身類的所有公用(public)方法包括私有(private)方法,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。
返回數組中的元素沒有排序,也沒有任何特定的順序。如果該類或接口不聲明任何方法,或者此 Class 對象表示一個基本類型、一個數組類或 void,則此方法返回一個長度為 0 的數組。
類初始化方法 <Constructor> 不包含在返回數組中。如果該類聲明帶有相同參數類型的多個公共成員方法,則它們都包含在返回的數組中。
getMethod(s):返回某個類的所有公用(public)方法包括其繼承類的公用方法,當然也包括它所實現接口的方法。這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
數組類返回從 Object 類繼承的所有(公共)member 方法。
返回數組中的元素沒有排序,也沒有任何特定的順序。如果此 Class 對象表示沒有公共成員方法的類或接口,或者表示一個基本類型或 void,則此方法返回長度為 0 的數組。
總之:getDeclaredMethods的關鍵詞是:自身,所有方法,不繼承而getMethods的關鍵詞是public 繼承
getDeclaredField(s)和getField(s)同上。
getDeclaredAnnotation(s):返回直接存在於此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在於此元素上,則返回長度為零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。
getAnnotation(s):返回此元素上存在的所有注釋。(如果此元素沒有注釋,則返回長度為零的數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。
getDeclaredAnnotations得到的是當前成員所有的注釋,不包括繼承的。而getAnnotations得到的是包括繼承的所有注釋。
關鍵在於繼承的問題上,getDeclaredAnnotations和getAnnotations是否相同,就在於父類的注解是否可繼承,這可以用sun.reflect.annotation.AnnotationType antype3=AnnotationType.getInstance(Class.forName(annotationtype_class(example:"javax.ejb.Stateful")).isInherited())來判定,如果為true,說明可以被繼承則存在與getAnnotations之中而不在getDeclaredAnnotations之中,否則,也不存在與getannnotations中,因為不能被繼承。
舉例說明:
首先,創建自定義注解和創建一個接口相似,但是注解的interface關鍵字需要以@符號開頭。我們可以為注解聲明方法。
注意事項:
- 注解方法不能帶有參數;
- 注解方法返回值類型限定為:基本類型、String、Enums、Annotation或者是這些類型的數組;
- 注解方法可以有默認值;
- 注解本身能夠包含元注解,元注解被用來注解其它注解。
package com.cj.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target(ElementType.METHOD) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface MethodInfo{ String author() default "Pankaj"; String date(); int revision() default 1; String comments(); }
這里有四種類型的元注解:
1. @Documented —— 指明擁有這個注解的元素可以被javadoc此類的工具文檔化。這種類型應該用於注解那些影響客戶使用帶注釋的元素聲明的類型。如果一種聲明使用Documented進行注解,這種類型的注解被作為被標注的程序成員的公共API。
2. @Target——指明該類型的注解可以注解的程序元素的范圍。該元注解的取值可以為TYPE,METHOD,CONSTRUCTOR,FIELD等。如果Target元注解沒有出現,那么定義的注解可以應用於程序的任何元素。
3. @Inherited——指明該注解類型被自動繼承。如果用戶在當前類中查詢這個元注解類型並且當前類的聲明中不包含這個元注解類型,那么也將自動查詢當前類的父類是否存在Inherited元注解,這個動作將被重復執行知道這個標注類型被找到,或者是查詢到頂層的父類。
4.@Retention——指明了該Annotation被保留的時間長短。RetentionPolicy取值為SOURCE,CLASS,RUNTIME。
Java內建注解
Java提供了三種內建注解。
1. @Override——當我們想要復寫父類中的方法時,我們需要使用該注解去告知編譯器我們想要復寫這個方法。這樣一來當父類中的方法移除或者發生更改時編譯器將提示錯誤信息。
2. @Deprecated——當我們希望編譯器知道某一方法不建議使用時,我們應該使用這個注解。Java在javadoc 中推薦使用該注解,我們應該提供為什么該方法不推薦使用以及替代的方法。
3. @SuppressWarnings——這個僅僅是告訴編譯器忽略特定的警告信息,例如在泛型中使用原生數據類型。它的保留策略是SOURCE(譯者注:在源文件中有效)並且被編譯器丟棄。
來看一個java內建注解的例子參照上邊提到的自定義注解。
package com.cj.Annotation; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; public class AnnotationExample { @Override @MethodInfo(author = "Pankaj", comments = "Main method", date = "Nov 17 2012", revision = 1) public String toString() { return "Overriden toString method"; } @Deprecated @MethodInfo(comments = "deprecated method", date = "Nov 17 2012") public static void oldMethod() { System.out.println("old method, don't use it."); } @SuppressWarnings({ "unchecked", "deprecation" }) @MethodInfo(author = "Pankaj", comments = "Main method", date = "Nov 17 2012", revision = 10) public static void genericsTest() throws FileNotFoundException { List l = new ArrayList(); l.add("abc"); oldMethod(); } }
Java注解解析
我們將使用反射技術來解析java類的注解。那么注解的RetentionPolicy應該設置為RUNTIME否則java類的注解信息在執行過程中將不可用那么我們也不能從中得到任何和注解有關的數據。
package com.cj.Annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class AnnotationParsing { public static void main(String[] args) { try { ClassLoader loader =AnnotationParsing.class.getClassLoader(); // Class src = loader.loadClass("com.cj.Annotation.AnnotationParsing"); Class className=loader.loadClass("com.cj.Annotation.AnnotationExample"); //Method[] methodss=src.getMethods(); Method[] methods = className.getMethods(); for (Method method : methods) { // checks if MethodInfo annotation is present for the method if (method.isAnnotationPresent(com.cj.Annotation.MethodInfo.class)) { try { // iterates all the annotations available in the method for (Annotation anno : method.getDeclaredAnnotations()) { System.out.println("Annotation in Method "+ method + " : " + anno); } MethodInfo methodAnno = method.getAnnotation(MethodInfo.class); // if (methodAnno.revision() == 1) { System.out.println("Method with revision no 1 = "+ methodAnno); //} } catch (Throwable ex) { ex.printStackTrace(); } } } } catch (SecurityException | ClassNotFoundException e) { e.printStackTrace(); } } }
參考網址:
https://my.oschina.net/itgaowei/blog/1602277
http://blog.sina.com.cn/s/blog_605f5b4f0100i77k.html
http://www.importnew.com/17413.html