註解(Annotation)是Java5中的新特性,一直看到很多項目在使用,但是自己一直不是很瞭解,現在有機會學習了一下,記錄下來,今後用得着。
1.註解可以做什麼?
註解將一些系統所需的數據信息(不方便用Java語言來表達),加入到了Java源代碼中,而不需要額外的信息提供者。比如配置信息、一些樣板文件(接口文件)等。可以通過在代碼中添加註解,來直接配置你的系統。
著名的Java單元測試框架Junit-4就是大量使用了註解的功能,加入到了其單元測試中,方面了用戶使用JUnit進行測試,用戶只需要在想要測試的方法上添加@Test 這樣的標籤就可以將該方法變爲一個單元測試用例。
下面,我將仿照JUnit的測試框架來簡單介紹一下註解功能(例子來自於java.sun.com)
2.註解怎麼使用
我把註解的使用分爲三個步驟:
第一,定義註解
第二,給源程序添加註解
第三,解析註解(實際工作在這裏完成)
首先看定義註解
註解的定義看起來和定義接口差不多,就是在interface關鍵字前多一個@標籤
/** * Describes the Request-For-Enhancement(RFE) that led * to the presence of the annotated API element. */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) public @interface RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date(); default "[unimplemented]"; }
其中的id()、synopsis()可以認爲是該註解的元素,或者屬性,這些方法聲明不能有任何參數,或者拋出異常,可以通過default 來定義它的默認值。而且這些類型只能是原語類型、String、Annotation或者這些類型的數組。
最上面的@Target表面了改註解使用的範圍(是一個方法還是一個類,或者一個域),@Retention表面了註解可以用在哪個級別上(源代碼中、類文件中、還是運行時)
這樣,便定義了一個註解
接下來給源程序添加註解:
@RequestForEnhancement(
id = 2868724,
synopsis = "Enable time-travel",
engineer = "Mr. Peabody",
date = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }
這樣就使用剛纔定義的RequestForEnhancement註解,描述了一個方法,可以看見在()中,定義了給該註解的各個元素的參數,就相當於初始化了該註解
最後解析註解,這裏我們使用一個簡單的測試框架來表述
定義一個Test註解,使用在運行時,定義在方法上,它沒有任何方法,只是一個標註
在解析程序中,獲取該標註,並採取相應動作。在這裏,使用了Test標籤標註的方法,都將被測試,並形成測試結果。
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 { }
添加將被測試的方法:
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() { }
}
在這裏用@Test標籤標註了m1 m3 m5 m7方法,這些方法將在運行測試用例時被測試。
在該類中運行了測試用例,它使用反射機制,調用了被標註爲@Test標籤的方法,如果拋出異常則認爲測試沒有通過,反之則通過。
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);
}
}
在這裏,可以講上面的這些類、註解可以和JUnit中的進行一個對比
@Test就是JUnit框架中的@Test
被標註的方法將被測試
RunTest類就相當於手動啓動JUnit進行單元測試時運行的org.junit.runner.JUnitCore.runClasses(不是使用IDE啓動測試用例,如果使用Eclipse類似的IDE,你可能只是點擊一個Run As JUnit)
這樣,就通過註解完成了一個簡單的測試框架
詳細信息可以查看
http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html