Annotations中文翻譯
2024-07-21 02:14:10
供稿:網友
by me
許多api都需要一定數量的樣板編碼。例如,為了寫一個jax-rpc web服務,你必須提供一對接口和實現組合。如果一個被遠程訪問的程序被注釋標識所裝飾,那么這個模板就可以利用工具來自動生成。
還有一些apis需要額外文件(side files)和程序一起并行來維持。例如,javabean需要一個beaninfo類和該bean一起并行維持,而企業級javabean(ejb)則需要一個配置描述符。如果在額外文件中的信息以程序注釋的形式保存在程序本身中,那將更加便利并且使錯誤傾向更少。
java平臺已經擁有了特別的注釋機制。例如transient修飾是一個特別的注釋標識:該區域應該被連續子系統忽略。而@deprecated標識是一種特殊注釋標識:方法不應該再被使用。到了5.0版本中,該平臺擁有一個多目的的工具就是允許你定義并使用你自己的注釋類型。這種工具包括聲明注釋類型的語法,注釋聲明的語法,讀取注釋的apis,表示注釋的類文件和一個注釋處理工具。
注釋不直接影響程序的語義,但是它們影響工具和庫處理該程序的方法,這樣就能夠轉過去影響運行時程序的語義。注釋從源文件,類文件中被讀取,或者在運行時反映出來。
典型的應用程序從來不必定義一個注釋類型,但這樣做也不難。注釋類型聲明于正常的接口(interface)聲明相似。在關鍵字interface前加個@符號。每一個方法聲明定義一個注釋類型的元素。方法聲明不必有參數或throws語句。返回值被限制為原始的string,class,enums,annotations和以上類型array。方法可以由缺省值。這是一個注釋類型聲明的例子:
/**
* 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)能夠使用的任何地方。根據協定,注視應先于其它修飾成分。注釋由一個at符號@跟著注釋類型和括號括起來的元素值對列表。這些值必須是編譯時的常量。這里有一個帶有注釋的對應上述注釋類型聲明的方法聲明:
@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 { }
在marker注釋中省略括號是可以的,比如:
@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 { ... }
為了把所有的聯系起來,我們將建立一個簡單的 基于注釋的測試框架。首先我們需要一個marker注釋類型來指出一個方法是一個測試方法,并且應該被測試工具來執行:
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 { }
注意這個注釋類型聲明是自注釋的。這樣的注釋被叫做meta-annotations。第一個(@retention(retentionpolicy.runtime))指出帶有這種類型的注釋被虛擬機保留,因此它們能夠在運行時反映出來。第二個(@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注釋類型(上面定義的)注釋的方法的方法。這個映射隊列來找出是否一個方法有一個被用綠色強調的test注釋。如果測試方法啟動拋出一個異常,測試則被認為已經失敗。并且一個失敗報告被打印出來。最后。一個摘要被打印出來顯示通過和失敗的測試的數量。這是在foo程序上運行這個測試工具的情況:
$ 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
這個小的測試工具示范了注釋的功效,也可以被輕松擴展來克服它的限制。