J2SE 5.0 在 java.lang.reflect 核心類別(Class、Method、Field、Constructor、Package)中引入 AnnotatedElement 介面,提供統一的註解查詢方法:
| 方法 | 用途 |
|---|---|
isAnnotationPresent(Class<? extends Annotation>) | 判斷是否存在指定註解 |
getAnnotation(Class<T>) | 取得指定註解實例(含屬性值) |
getAnnotations() | 取得所有註解(含繼承) |
getDeclaredAnnotations() | 取得直接宣告的註解(不含繼承) |
// 方法級註解,含優先屬性
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TODO {
int priority() default 0;
}
// 欄位級註解,標記需格式化
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TOFORMAT { }
public class MyCalculator {
boolean isReady;
@TOFORMAT double concurrency;
@TOFORMAT Date debitDate;
@TODO(priority = 5)
public void calculateRate() {
System.out.println("Calculating...");
}
}
public class TestCalculator {
public static void main(String[] args) {
MyCalculator cal = new MyCalculator();
cal.calculateRate(); // 正常業務邏輯
try {
Class<?> clazz = cal.getClass();
// 掃描方法註解
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(TODO.class)) {
TODO todo = m.getAnnotation(TODO.class);
System.out.println("Method: " + m.getName()
+ ", TODO present, priority=" + todo.priority());
}
}
// 掃描欄位註解
for (Field f : clazz.getDeclaredFields()) {
if (f.isAnnotationPresent(TOFORMAT.class)) {
System.out.println("Field: " + f.getName() + ", TOFORMAT present");
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
Calculating... Method: calculateRate, TODO present, priority=5 Field: concurrency, TOFORMAT present Field: debitDate, TOFORMAT present

@Retention(RUNTIME) 是執行期反射讀取的前提條件。若為 SOURCE 或 CLASS,執行期 isAnnotationPresent 永遠返回 false。getDeclaredMethods/Fields() 不含繼承:僅掃描該類別直接宣告的成員。需掃描繼承鏈請自行遞迴 getSuperclass()。m.getAnnotation(TODO.class).priority() 像呼叫普通方法一樣存取註解屬性。priority 時自動為 0(編碼在註解類別的 default 子句)。| 模式 | 關鍵註解 | 掃描時機 | 典型用途 |
|---|---|---|---|
| 編譯期代碼生成 | @GenerateBuilder, @Entity | APT / javac -processor | Lombok、MapStruct、JPA 實體增強 |
| 啟動期掃描裝配 | @Component, @Autowired | Classpath 掃描 | Spring、Guice 依賴注入 |
| 執行期攔截驗證 | @NotNull, @Valid | 方法呼叫攔截 | Bean Validation、AOP 參數檢查 |
| 文件/報表生成 | @Exportable, @ApiDoc | 按需觸發 | Swagger、自動化測試報告 |
@TODO( 後按 Ctrl+Space 顯示 priority() 屬性。method. 列出 isAnnotationPresent、getAnnotation 等關鍵方法。RUNTIME 卻嘗試反射讀取,Eclipse 可配置警告並一鍵添加。Field/Method 物件可展開查看 annotations 陣列。執行期反射動態查找註解是「註解驅動開發」的基石。掌握 AnnotatedElement 四大查詢方法、務必加上 @Retention(RUNTIME)、善用 getAnnotation() 存取屬性值,即可構建靈活的掃描器、驗證器、生成器等工具。Eclipse 3.1 以智能提示與警告機制,將這套機制的正確使用內化為開發流程的自動防呆。