承接第一部分 (內建註解 @Override、@Deprecated、@SuppressWarnings),本文深入自訂註解類型定義、成員設計、預設值、以及元註解 (註解的註解) 完整機制。
@interface 宣告語法類似介面,但 interface 前加 @。最簡單範例:
package com.oreilly.tiger.ch06;
/** 標記註解:指示方法/類別仍在處理中 */
public @interface InProgress { }
使用方式與內建註解相同:
@com.oreilly.tiger.ch06.InProgress
public void calculateInterest(float amount, float rate) { /* ... */ }
可 import 後直接用 @InProgress。
成員以無參方法形式宣告,方法名 = 成員名,回傳型別 = 成員型別。無需 getter/setter。
public @interface TODO {
String value(); // 單一成員慣命名為 value
}
使用:
@TODO("Figure out the amount of interest per month")
public void calculateInterest(float amount, float rate) { /* ... */ }
簡寫規則:僅當註解類型只有單一成員且名為 value 時,可省略成員名直接給值。否則需完整寫法:
@TODO(value = "Figure out the amount of interest per month")
在成員宣告後加 default 關鍵字:
public @interface GroupTODO {
public enum Severity { CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION }
Severity severity() default Severity.IMPORTANT;
String item();
String assignedTo();
String dateAssigned();
}
使用時可省略預設值成員:
@GroupTODO(
item = "Figure out the amount of interest per month",
assignedTo = "Brett McLaughlin",
dateAssigned = "08/04/2004"
// severity 將自動套用 IMPORTANT
)
也可顯式覆寫:
@GroupTODO(
severity = GroupTODO.Severity.DOCUMENTATION,
item = "Need to explain how this rather unusual method works",
assignedTo = "Jon Stevens",
dateAssigned = "07/30/2004"
)
四種預定義元註解,賦予自訂註解語義約束與行為控制。
參數為 ElementType 列舉陣列:
public enum ElementType {
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE
}
範例:限定 @TODO 僅能用於類型、方法、建構子、其他註解類型:
@Target({ElementType.TYPE, ElementType.METHOD,
ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
public @interface TODO { String value(); }
編譯器將阻止錯誤使用位置 (如套用在欄位上)。
參數為 RetentionPolicy 列舉:
public enum RetentionPolicy {
SOURCE, // 編譯器捨棄,不進 class 檔
CLASS, // 存入 class 檔,但 VM 忽略 (預設)
RUNTIME // 存入 class 檔,VM 載入可透過反射讀取
}
範例:@SuppressWarnings 僅需原始碼階段生效:
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings { /* ... */ }
CLASS 為預設,無需顯式聲明。
標記註解 (無成員)。預設註解**不出現在 Javadoc** 中。加上此元註解可將註解資訊輸出至類別 HTML 文件。
@Documented
@Retention(RetentionPolicy.RUNTIME) // 必須為 RUNTIME
public @interface InProgress { }
關鍵:Javadoc 從 class 檔透過 VM 讀取資訊,**必須設定 RUNTIME 保留策略**,否則 Javadoc 讀不到。
預設註解**不會**被子類別繼承。加上此元註解後,父類別的註解會出現在子類別中 (透過反射可見)。
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
適用場景:標記類別狀態 (如「開發中」) 需傳遞給子類。不適用:@TODO 等任務型註解不應傳遞。
package com.oreilly.tiger.ch06;
import java.lang.annotation.*;
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Feature {
String id();
String description() default "";
Status status() default Status.PLANNED;
public enum Status { PLANNED, IN_PROGRESS, COMPLETED, DEPRECATED }
}
使用:
@Feature(id = "AUTH-001", description = "OAuth2 整合", status = Feature.Status.IN_PROGRESS)
public class AuthService { /* ... */ }
@Override、@Deprecated、@SuppressWarnings、@FunctionalInterface、@SafeVarargs 等標準註解已涵蓋大多數需求@Target、@Retention,避免預設行為導致誤用SOURCE 不用 CLASS,能用 CLASS 不用 RUNTIME (除非需反射讀取或 Javadoc)String、Class、enum、註解類型、及上述類型的一維陣列value 享受簡寫語法;多成員採描述性名稱自訂註解 = @interface + 成員方法 + 元註解約束。@Target 限位置、@Retention 控生命週期、@Documented 進文件、@Inherited 傳子類。善用註解可構建強大的編譯期檢查、程式碼分析與框架整合能力,但**切勿濫用** — 最好的註解是「不寫也能懂」的程式碼本身。