註解三要素
- 定義:`@interface` 關鍵字 + 元註解標識目標/生命週期
- 使用:在類別、方法、欄位上標註,賦值屬性
- 解析:運行期透過反射 `getAnnotation()` 讀取屬性值
元註解詳解
| 元註解 | 作用 | 常用值 |
| @Target | 限制註解可標註位置 | TYPE(類別)、FIELD(欄位)、METHOD(方法)、PARAMETER(參數)、CONSTRUCTOR(建構子)、LOCAL_VARIABLE、ANNOTATION_TYPE、PACKAGE、TYPE_PARAMETER、TYPE_USE |
| @Retention | 生命週期 | SOURCE(源碼期丟棄)、CLASS(編譯期保留、類檔案有、運行期無)、RUNTIME(運行期保留、可反射讀取) |
| @Documented | 納入 Javadoc | 無屬性 |
| @Inherited | 子類別繼承父類別註解 | 僅對 TYPE 生效 |
| @Repeatable | 可重複標註同一註解 (Java 8+) | 需配合容器註解 |
實戰:自訂 ORM 映射註解
1. 定義註解
// 表映射
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTable {
String name() default "";
String version() default "1";
}
// 欄位映射
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyField {
String name() default "";
String type() default "";
}
2. 使用註解
@MyTable(name = "T_BaseLog", version = "2")
public class BaseLog {
@MyField(name = "addTime", type = "Date")
private Date logTime;
@MyField(name = "logLevel", type = "String")
private String logLevel;
@MyField(name = "message", type = "String")
private String message;
// getter/setter 省略
}
3. 解析器實現
public class AnnotationParser {
public static void parse(Class<?> clazz) {
// 解析類別註解
MyTable table = clazz.getAnnotation(MyTable.class);
if (table != null) {
System.out.println("Table: " + table.name() + ", v" + table.version());
}
// 解析欄位註解
for (Field f : clazz.getDeclaredFields()) {
MyField field = f.getAnnotation(MyField.class);
if (field != null) {
System.out.printf("Field: %s → Column: %s, Type: %s%n",
f.getName(), field.name(), field.type());
}
}
}
public static void main(String[] args) {
parse(BaseLog.class);
}
}
4. 輸出結果
Table: T_BaseLog, v2
Field: logTime → Column: addTime, Type: Date
Field: logLevel → Column: logLevel, Type: String
Field: message → Column: message, Type: String
進階:註解屬性型別支援
public @interface AdvancedAnn {
String str() default "";
int num() default 0;
boolean flag() default false;
Class<?> clazz() default Object.class;
String[] arr() default {};
EnumType enumVal() default EnumType.A;
// 不支援:物件、巢狀註解(需 Java 8+ 容器)、方法參考
}
enum EnumType { A, B, C }
常見內建註解速查
| 註解 | 用途 | 來源 |
| @Override | 檢查是否正確重寫父類方法 | java.lang |
| @Deprecated | 標記過時 API | java.lang |
| @SuppressWarnings | 抑制編譯警告 | java.lang |
| @FunctionalInterface | 標記函數式介面 (單一抽象方法) | java.lang |
| @Nullable / @NonNull | 空值檢查輔助 (IDE/靜態分析) | JSR-305 / Lombok |
| @Autowired / @Component | 依賴注入 / 元件掃描 | Spring |
| @Entity / @Table / @Column | JPA 實體映射 | Jakarta Persistence |
最佳實踐
- ✅ 運行期解析**必須**加 `@Retention(RUNTIME)`
- ✅ 明確 `@Target` 限制使用位置,防止誤用
- ✅ 屬性命名用名詞,預設值語意化(如 `""`、`-1`、`false`)
- ✅ 解析器統一封裝,業務邏輯與反射細節解耦
- ⚠️ 避免過度設計:能用介面/繼承表達的語意,別硬用註解
註解是「宣告式程式設計」的核心工具。掌握「定義-使用-解析」三部曲,能讀懂 Spring、JPA、MyBatis 等主流框架的運作原理,也能為專案打造專屬的元資料驅動能力。