?在上篇文章里提到的是JUnit的學習,其中就涉及到了一些內置的annotation,如@Test、@Ignore等。現在我就結合個人的理解談下如何自定義自己的annotation。
? annotation能被用來為某個程序元素(類、方法、成員變量等)關聯任何的信息,但annotaion不能影響程序代碼的執行,無論增加、刪除annotation,代碼都始終如一的執行。另外,盡管一些annotation通過java的反射api方法在運行時被訪問,而java語言解釋器在工作時忽略了這些annotation。正是由于java虛擬機忽略了annotation,導致了 annotation類型在代碼中是“不起作用”的;只有通過某種配套的工具才會對annotation類型中的信息進行訪問和處理,因而使用簡便。
? 先說下定義annotation的語法。@interface是一個關鍵字,在自定義自己annotations的時候必須把一個類型定義為@interface,而不能用class或interface關鍵字,形如“public @interface MyAnnotation{ }”,以下是定義的幾個示例:
? 1.無任何方法/屬性Annotation
??
2,具有一個方法getValue( )的Annotation
3,? 具有一個特殊方法value( )的Annotation(特殊性下面會提到)
4,具有一個方法和屬性的Annotation
5,具有多個方法的Annotation
在上面的例子中可以看到,其實申明一個annotation和interface、class不同的是關鍵字@interface,而且它還可以對方法設置默認的返回值,如上圖的“? public int getSingleNumber() default 0 ;???? ”,設置默認返回0。還有個顯著的不同就是在申明每個Annotation的上面有幾個標簽@Target、@Retention。
? annotation的target是一個被標注的程序元素。target說明了annotation所修飾的對象范圍:annotation可被用于 packages、types(類、接口、枚舉、annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在annotation類型的聲明中使用了target可更加明晰其修飾的目標。annotation的retention定義了該annotation被保留的時間長短:某些annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請注意并不影響class的執行,因為annotation與class在使用上是被分離的)。使用這個meta-annotation可以對 annotation的“生命周期”限制。RetentionPolicy是一個enum類型,共有三個值,分別是SOURCE,CLASS 和 RUNTIME。SOURCE代表的是這個Annotation類型的信息只會保留在程序源碼里,源碼如果經過了編譯之后,Annotation的數據就會消失,并不會保留在編譯好的.class文件里面。ClASS的意思是這個Annotation類型的信息保留在程序源碼里,同時也會保留在編譯好的.class文件里面,在執行的時候,并不會把這一些信息加載到虛擬機(JVM)中去.注意一下,當你沒有設定一個Annotation類型的Retention值時,系統默認值是CLASS. 第三個,是RUNTIME,表示在源碼、編譯好的.class文件中保留信息,在執行的時候會把這一些信息加載到JVM中去的。
? 下面是如何使用自己定義的annotation:
?
從上面的測試代碼可以看出:使用一個annotation的語法是 由 “@+annotation 類型名稱 +(.. 逗號分割的 name-value 對 …)” 組成。其中成員可以按照任何的順序。如果 annotation 類型定義了某個成員的默認值,則這個成員可以被省略。成員值必須為編譯時常量、內嵌的 annotation 或者數組。
上面提到了一個特殊性,大家可以對比下上面的testMethod2和testMethod3上的annotation,會發現@OneMethodSpecialInAnnotation的值 ”Hello,world!”是沒有匹配的name,那么這個值 到底傳給誰了?其實這里有一個約定。如果沒有寫屬性名的值,而這個注釋又有 value 屬性,就將這個值賦給 value 屬性,相當于是(value=”Hello,world!”)。
main方法是一個對上面進行測試的,其輸出是:
the method testMethod1 is not wired!!
the method testMethod2 is not wired!!
the method testMethod3 is not wired!!
the method testMethod4 is not wired!!
the method testMethod5 is wired!!
為什么輸出“testMethod5 is wired”呢?因為執行了這句代碼:if (method.isAnnotationPresent(MultiMethodsInAnnotation.class))。@MultiMethodsInAnnotation是在testMethod5 上的,如果換成其他的annotation,也會得到相應的提示。isAnnotationPresent()方法對于檢查marker annotation是十分有用的,因為marker annotation沒有成員變量,所以我們只要知道class的方法是否使用了annotation修飾就可以了。而當處理具有成員的 annotation時,我們通過使用getAnnotation()方法來獲得annotation的成員信息(成員名稱、成員值)。這里我們看到了一套優美的java annotation系統:如果annotation存在,那么實現了相應的annotation類型接口的對象將被getAnnotation()方法返回,接著調用定義在annotation類型中的成員方法可以方便地獲得任何成員值。
? 現在我們再來個High點的,如何訪問一個annotation里的各個方法,如下:
? 至此,感覺自己學到的也就這么多了,也不知道是不是太膚淺。相信Annotation技術在不久的將來將得到更好的發展!至于在實際測試中用到的DBunit中的@DataSet macker是如何將場景數據自動插入到數據庫的源碼學習,將在以后的總結中給出。希望各位多提寶貴意見,支持新手哦!
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
