對於 Java 開發者而言,註解早已不再陌生。從早期的 @author、@param 配合 Javadoc 生成文檔,到 JDK 5.0(J2SE 1.5)正式引入註解機制,Java 賦予了「元資料」語言級的原生支援。這不僅改變了文檔生成方式,更為編譯期檢查、框架整合、程式碼分析奠定了基石。本文將系統梳理 JDK 5.0 註解的核心語法、標準註解用法、自定義註解定義與反射獲取,並附帶實戰程式碼示例。
註解本質上是「關於程式碼的資料」。它們不直接影響程式邏輯,但可被編譯器、開發工具或執行期框架讀取,用於:
早期依賴 XDoclet 等工具透過特殊標籤實現類似功能,JDK 5.0 將其標準化為語言特性,標記符號沿用 @ 符號。
JDK 5.0 提供三個核心標準註解,其中 @Override 最具實戰價值。
當子類意圖覆寫父類方法時,加上 @Override 可強制編譯器驗證父類確實存在該方法簽名。若不慎拼寫錯誤(如 foo() 寫成 fob()),編譯器將直接報錯:
Child.java:3: method does not override a method from its superclass
@Override
^
1 error
這能在開發早期攔截低級錯誤,避免運行期難以排查的 Bug。
public class Parent {
public void foo() {
System.out.println("Original Implementation of foo");
}
}
public class Child extends Parent {
@Override
public void foo() {
System.out.println("Override Implementation of foo");
}
}
開發者可透過 @interface 定義專屬註解類型,支援成員變數與預設值。
package tiger.annotation;
public @interface MyTag {
String name();
int age();
}
import tiger.annotation.MyTag;
public class TagTest {
@MyTag(name = "MyTag", age = 1)
public void testTag() { }
}
若需在執行期透過反射讀取註解,必須標註 @Retention(RetentionPolicy.RUNTIME),否則反射獲取結果為空。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
String name();
int age();
}
透過 java.lang.reflect.AnnotatedElement 介面可讀取運行時保留的註解:
import java.lang.annotation.Annotation;
import tiger.annotation.MyTag;
public class TagTest {
@MyTag(name = "MyTag", age = 1)
public void test() { }
public static void main(String[] args) {
TagTest tt = new TagTest();
try {
Annotation[] annotations = tt.getClass().getMethod("test").getAnnotations();
for (Annotation tag : annotations) {
System.out.println("Tag is: " + tag);
System.out.println("tag.name() = " + ((MyTag) tag).name());
System.out.println("tag.age() = " + ((MyTag) tag).age());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Tag is:@tiger.annotation.MyTag(name=MyTag, age=1)
tag.name()MyTag
tag.age()1
掌握基礎語法後,註解的真正威力在於「註解處理器」與框架整合:
更多詳細規格請參考 官方文檔。本文所有程式碼已在 Win2K + J2SE 5.0 GA 環境驗證通過。