J2SE 5.0 (Tiger) 發布是 Java 語言發展史上重要里程碑,迄今為止 Java 程式設計領域最大進步。新特性包括:泛型、列舉類型、中繼資料/註解、自動拆箱/裝箱、可變參數、靜態導入、新執行緒框架。Eclipse 3.1 M4 起支援 J2SE 5.0 開發。
本系列介紹三大重要特性:列舉類型、註解類型、泛型,並示範在 Eclipse 3.1 開發環境中的應用。本文聚焦註解類型。
J2SE 5.0 支援中繼資料,在原始檔中稱為註解。開發者可在不改變原有邏輯下,在原始檔嵌入補充資訊。程式碼分析工具、開發工具、部署工具可透過這些資訊驗證或部署。例如希望某方法參數或回傳值不為 null,雖可在 JavaDoc 說明,但自然語言表達多樣,工具難以分析。使用註解即能輕鬆解決。
使用 @interface 關鍵字聲明註解。最簡單範例:
public @interface TODO {}
可在註解中加入元素(類似方法,無需 getter/setter):
public @interface TODO {
String priority();
}
使用自訂註解:
@TODO(priority="high")
public void calculate() { /* body */ }
單一元素可簡寫:@TODO("high")。可定義多元素與預設值:
public @interface TODO {
String priority();
String owner();
boolean testable() default true;
}
使用時可省略預設值元素:
@TODO(priority="high", owner="Catherine")
public void calculate() { /* testable 使用預設 true */ }
com.catherine.lab.annotation.demo。TODO,點擊 Finish 生成程式碼。

依傳入參數數目分三種:
@Override、@Deprecated 屬此類。語法:@MarkerAnnotation。若註解所有元素皆有預設值,也可視為標記註解。@SingleValueAnnotation("some value")。@MultipleValueAnnotation(key1=value1, key2=value2, key3=value3)。J2SE 5.0 預定義三種註解:
java.lang.Override):表示當前方法覆寫父類方法,若父類無對應方法則編譯錯誤。java.lang.Deprecated):不建議使用當前方法或欄位。java.lang.SuppressWarnings):關閉編譯器警告,編譯 1.5 前程式碼時避免大量無關警告。在模板方法模式中極具價值。抽象類定義主要控制流,子類透過覆寫父類方法實現邏輯。若父類提供預設實作,子類可選擇不實作。問題在於:若子類想覆寫但拼錯方法名,編譯器會視為新方法而非覆寫,難以發現。使用 @Override 後,拼錯會導致編譯錯誤提示父類無對應方法。

public abstract class BaseClass {
public void doWork() {
doPartI();
doPartII();
}
public abstract void doPartI();
public void doPartII() {}
}
public class SubClass extends BaseClass {
public void doPartI() {}
@Override
public void doPortII() { // 故意拼錯
System.out.println("override the method of superclass");
}
}

J2SE 5.0 提供四種用於註解的註解類型:
@Override 僅能修飾方法。範例:@Target({ElementType.METHOD}) 限定 @TODO 僅能修飾方法,修飾類別或欄位會編譯錯誤(見圖 5)。RetentionPolicy.SOURCE:編譯後從 class 檔移除RetentionPolicy.CLASS:保留在 class 檔,VM 不處理(預設)RetentionPolicy.RUNTIME:保留在 class 檔,VM 處理(運行時需透過反射讀取註解必須指定此策略)定義註解後可開發分析工具解讀,通常利用 Java 反射特性。範例定義 @TODO(修飾方法)與 @TOFORMATE(修飾欄位),在 MyCalculator 使用,TestCalculator 透過反射查找使用這些註解的方法與欄位(見清單 12-15)。運行結果與定義一致,可在運行時獲取註解使用資訊。

J2SE 5.0 前常用 Visitor 模式 為既有類別結構添加方法而不修改原類別。例如輸出物件部分資料至特定格式檔案。Visitor 實作需在 Employee 加入 export 方法接受 Exporter 物件並呼叫 visit()。定義 Exporter 抽象類,繼承並覆寫 visit() 實現不同格式輸出。缺點:若 Employee 新增欄位,對應 Visitor 類也需修改,違反「開放擴充、封閉修改」原則。

使用註解替代:定義 @Exportable 註解,建立抽象解析器 ExportableGenerator 傳入 Employee 物件,解析器查找使用 @Exportable 的欄位並按格式輸出。定義見清單 16。Employee、Regular、Vendor、Contractor、Supplemental 類別使用 @Exportable 標記需輸出欄位(清單 17-21)。TestExportable 使用 ExportableGenerator 產生輸出檔(清單 22)。ExportableGenerator 定義基本框架(清單 23),TXTExportableGenerator 繼承並實作具體輸出格式(清單 24)。使用者可繼承實作抽象方法定義期望格式。
範例將 Employee 物件部分內容輸出至 C:\test.output,結果見圖 12。透過此法可動態生成物件欄位輸出,無需在程式碼寫死輸出欄位。若需豐富格式,可定義多種註解類型,透過解析不同註解與屬性實現格式化輸出。

中繼資料即「關於資訊的資訊」。程式碼分析、測試、部署工具常用中繼資料產生配置資訊與控制邏輯,通常利用 Java 反射重構並解釋中繼資料。新技術改變程式設計與開發者設計思維。註解不僅用於程式碼分析、測試/部署框架,應用範圍極廣。善用中繼資料可提升軟體品質與可維護性。