JDK5.0中注釋(Annotation)的用法

來源:互聯網
上載者:User

很多API都需要相當數量的樣板代碼,比如,為了編寫一個JAX-RPC的WEB服務,你需要提供一個介面和一個實作類別。如果這個程式已經被加了注釋Annotations以說明那個方法需要被遠程調用,那麼我們可以一個工具去自動產生這些樣板代碼。



還有一些API需要在程式碼另外維護一些檔案,比如JavaBean需要一個BeanInfo類,EJB需要一個部署描述檔案。如果我們能夠把這些需要另外維護的檔案內容以注釋Annotation的方式和代碼放在一起維護,一定會更加方便同時也減少出錯的機會。



Java平台已經有了一些特別的注釋的機制。比如transient修飾符就是一個特別的注釋,表明這個欄位應該被序列化子系統忽略;@deprecated javadoc標籤是一個特別的標籤來說明某個方法已經不再被使用了。JDK5.0提供了一個讓我們自己定義我們自己注釋的功能,這個功能包含了如何定義注釋類型的文法,聲明注釋的文法,讀取注釋的API,一個類檔案儲存注釋(譯者註:注釋可以被看作一個類,我們需要用一個.java檔案儲存我們自己定義的注釋源碼)和一個注釋處理的工具。



注釋並不影響代碼的語義,但卻影響用於處理包含有注釋的程式碼的工具的處理方式,使他們(工具)能夠影響運行狀態的程式的語義。注釋可以從原始碼中讀取,從編譯後的.class檔案中讀取,也可以通過反射機制在運行時讀取。



注釋是JavaDoc標籤的補充。一般情況下,如果我們的主要目標是影響或者產生文檔,那麼我們應該使用JavaDoc;否則,我們應該使用注釋Annotations。



一般的應用程式開發人員可能從不需要定義一個注釋類型,但定義我們自己的注釋類型並不複雜。注釋類型的定義跟定義一個介面相似,我們需要在interface這個關鍵字前面加上一個@符號。注釋中的每一個方法定義了這個注釋類型的一個元素,注釋中方法的聲明中一定不能包含參數,也不能拋出異常;方法的傳回值被限制為簡單類型、String、Class、emnus、注釋,和這些類型的數組。方法可以有一個預設值。這裡是一個注釋類型定義的例子:

/*** Describes the Request-For-Enhancement(RFE) that led* to the presence of the annotated API element.*/public @interface RequestForEnhancement {    int    id();    String synopsis();    String engineer() default "[unassigned]";     String date();    default "[unimplemented]"; }



一旦定義好了一個注釋類型,你就可以用來作注釋聲明。注釋一中特殊的修飾符,在其他修飾符(比如public,static,或者final等)使用地方都可以使用。按照慣例,注釋應該放在其他修飾符的前面。注釋的聲明用@符號後面跟上這個注釋類型的名字,再後面跟上括弧,括弧中列出這個注釋中元素/方法的key-value對。值必須是常量。這裡是一個例子,使用上面定義的注釋類型:




@RequestForEnhancement(



    id       = 2868724,



    synopsis = "Enable time-travel",



    engineer = "Mr. Peabody",



    date     = "4/1/3007"



)



public static void travelThroughTime(Date destination) { ... }





 


沒有元素/方法的注釋被成為標記(marker)注釋類型,例如




 



/**



* Indicates that the specification of the annotated API element



* is preliminary and subject to change.



*/



public @interface Preliminary { }




 



標記注釋在使用的時候,其後面的括弧可以省略,例如:








@Preliminary public class TimeTravel { ... }








如果注釋中僅包含一個元素,這個元素的名字應該為value,例如:








/**

* Associates a copyright notice with the annotated API element.

*/

public @interface Copyright { String value(); }






如果元素的名字為value,使用這個注釋的時候,元素的名字和等號可以省略,如:








@Copyright("2002 Yoyodyne Propulsion Systems")

public class OscillationOverthruster { ... }






為了將上面提到的東西結合在一起,我們建立了一個簡單的基於注釋的測試架構。首先我們需要一個標記注釋類型用以說明一個方法是一個測試方法,並被測試載入器執行。




 



import java.lang.annotation.*;




 


/**



* Indicates that the annotated method is a test method.



* This annotation should be used only on parameterless static methods.



*/



@Retention(RetentionPolicy.RUNTIME)



@Target(ElementType.METHOD)



public @interface Test { }





 


我們可以注意到這個注釋類型本省也被注釋了,這種注釋叫做元注釋。第一注釋(@Retention(RetentionPolicy.RUNTIME))表示這種類型的注釋被VM保留從而使其能夠通過反射在運行時讀取;第二個注釋@Target(ElementType.METHOD)表示這種注釋只能用來注釋方法。




 


下面是一個簡單的類,其中的幾個方法被加了上面的注釋:




 



public class Foo {



    @Test public static void m1() { }



    public static void m2() { }



    @Test public static void m3() {



        throw new RuntimeException("Boom");



    }



    public static void m4() { }



    @Test public static void m5() { }



    public static void m6() { }



    @Test public static void m7() {



        throw new RuntimeException("Crash");



    }



    public static void m8() { }



}





 


這裡是測試載入器:




 



import java.lang.reflect.*;




 


public class RunTests {



   public static void main(String[] args) throws Exception {



      int passed = 0, failed = 0;



      for (Method m : Class.forName(args[0]).getMethods()) {



         if (m.isAnnotationPresent(Test.class)) {



            try {



               m.invoke(null);



               passed++;



            } catch (Throwable ex) {



               System.out.printf("Test %s failed: %s %n", m, ex.getCause());



               failed++;



            }



         }



      }



      System.out.printf("Passed: %d, Failed %d%n", passed, failed);



   }



}





 


這個工具用一個類名作為參數,遍曆這個類中的所有方法,並調用其中被加了@Test注釋的方法。如果一個方法拋出了一個異常,那麼這個測試就失敗了,最終的測試結果被列印了出來。下面是程式啟動並執行結果:




 



$ java RunTests Foo



Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom



Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash



Passed: 2, Failed 2





 



 


雖然這個測試載入器只是一個玩具,但他顯示了注釋的強大的功能。




相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。