隨筆-6  評論-38  文章-40  trackbacks-0

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

          很多 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

          		

          ?

          ?

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

          ?

          posted on 2006-11-26 20:04 一手的小窩窩 閱讀(394) 評論(0)  編輯  收藏 所屬分類: JAVA
          主站蜘蛛池模板: 浦北县| 连江县| 邓州市| 禄丰县| 嘉荫县| 册亨县| 沁水县| 永顺县| 缙云县| 澄城县| 女性| 嘉祥县| 蓬安县| 徐水县| 宜丰县| 桂平市| 新密市| 裕民县| 隆德县| 贡山| 大足县| 治县。| 团风县| 平舆县| 卢湾区| 波密县| 开封市| 抚顺市| 澎湖县| 伊宁市| 英德市| 阿克| 华容县| 镇沅| 东丰县| 汶上县| 渝北区| 屏东市| 阜南县| 武宁县| 修文县|