Annotation(註解)自 Java 5 引入以來,已成為框架開發、配置元數據、編譯檢查的基石。本文從四大內建註解切入,帶你手寫自定義註解、理解 @Target、@Retention、@Documented 元註解語義,並示範如何透過反射在運行時解析註解屬性,打通「聲明式編程」最後一公里。
| 註解 | 用途 | 適用位置 |
|---|---|---|
@Override | 標示方法覆寫父類/介面方法,編譯器檢查簽名一致性 | 方法 |
@Deprecated | 標示 API 過時,編譯器發出警告,建議遷移 | 類、方法、欄位、建構子、套件、參數等所有元素 |
@SuppressWarnings | 壓制編譯器特定警告(如 unchecked、rawtypes、deprecation) | 類、方法、欄位、區域變數等 |
@Entity | JPA 標示可持久化實體類(非 JDK 內建,屬 javax.persistence) | 類 |
value 名稱)package com.example.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE) // 只能標註在類/介面/Enum/註解上
@Retention(RetentionPolicy.RUNTIME) // 保留至運行期,可被反射讀取
@Documented // 納入 Javadoc 生成的 API 文檔
public @interface Description {
String value(); // 單一屬性,名稱慣用 value,使用時可省略屬性名
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuditLog {
String description(); // 業務描述
boolean enabled() default true; // 可提供預設值
int level() default 1; // 審計等級
}
@Description("訂單核心領域模型")
public class Order {
@AuditLog(description = "建立訂單", level = 2)
public void create() { /* ... */ }
@AuditLog(description = "取消訂單", enabled = false)
public void cancel() { /* ... */ }
}
| 元註解 | 關鍵屬性 | 語義 |
|---|---|---|
@Target |
ElementType[] value |
限制註解可標註的程式元素類型:
|
@Retention |
RetentionPolicy value |
生命週期策略:
|
@Documented |
無 | 指示 Javadoc 工具將此註解類型包含在生成的 API 文檔中。缺省不顯示。 |
@Inherited |
無 | **僅對 @Target(TYPE) 有效**。標註此元註解的註解,若父類被標註,子類透過 getAnnotation 可繼承獲取(不包含介面實作)。 |
@Repeatable |
Class<? extends Annotation> value |
(Java 8+) 允許同一位置重複標註同類型註解,需配合容器註解。 |
註解屬性(方法)僅支援以下類型:
byte, short, int, long, float, double, char, booleanStringClass (含型別參數)EnumAnnotation (嵌套註解)String[])⚠️ 不支援:null 作為預設值、泛型、多維陣列、物件實例。
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class AnnotationParser {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.example.annotation.Order");
// 1. 解析類級註解
if (clazz.isAnnotationPresent(Description.class)) {
Description desc = clazz.getAnnotation(Description.class);
System.out.println("📦 類描述: " + desc.value());
}
// 2. 解析方法級註解
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(AuditLog.class)) {
AuditLog audit = method.getAnnotation(AuditLog.class);
System.out.printf("🔧 方法: %-10s | 描述: %-10s | 啟用: %b | 等級: %d%n",
method.getName(), audit.description(), audit.enabled(), audit.level());
}
}
}
}
📦 類描述: 訂單核心領域模型 🔧 方法: create | 描述: 建立訂單 | 啟用: true | 等級: 2 🔧 方法: cancel | 描述: 取消訂單 | 啟用: false | 等級: 1
@Retention(SOURCE) + javax.annotation.processing,編譯階段生成代碼/配置/檢查(如 Lombok、MapStruct、Dagger)。@Target(PARAMETER) 結合 Method.getParameterAnnotations() 實現聲明式參數校驗、綁定(如 Spring MVC @RequestParam)。@Target 與 @Retention,避免濫用預設值導致語義模糊。value**,使用時可簡寫 @Anno("val")。default 值,降低使用者負擔。@Documented,方便 API 使用者查閱。Annotation 物件或改用編譯期處理。Annotation 是 Java「聲明式編程」的基石。掌握 元註解語義、屬性類型限制、保留策略選擇、反射解析 API,即可從「使用框架註解」進階到「設計領域專用註解」,構建乾淨、可擴展、自文檔化的代碼庫。