Meta-Annotation(元註解)完整定義
定義於 java.lang.annotation 套件,用於約束註解本身的行為:
| Meta-Annotation | 用途 | 關鍵屬性 |
@Target | 限定註解可標註的程式元素類型 | value() — ElementType[] |
@Retention | 限定註解保留階段 | value() — RetentionPolicy |
@Documented | 標示該註解應出現在 Javadoc 中 | 無屬性 |
@Inherited | 標示該註解可被子類別繼承(僅對類別有效) | 無屬性 |
@Target — ElementType 列舉值
TYPE // 類別、介面、Enum、註解類型
FIELD // 欄位(含 Enum 常數)
METHOD // 方法(不含建構子)
PARAMETER // 方法參數
CONSTRUCTOR // 建構子
LOCAL_VARIABLE // 區域變數、catch 參數
ANNOTATION_TYPE // 註解類型(元註解)
PACKAGE // 套件宣告
MODULE // Java 9+ 模組宣告
TYPE_PARAMETER // Java 8+ 型別參數
TYPE_USE // Java 8+ 型別使用處
@Retention — RetentionPolicy 三階段
SOURCE // 僅原始碼階段,編譯器捨棄,不進 .class(如 @Override、@SuppressWarnings)
CLASS // 進 .class,但 VM 載入時捨棄(預設值)
RUNTIME // 進 .class 且 VM 載入時保留,可透過反射讀取(自訂註解常用)
三大標準註解
| 註解 | 套件 | 用途 | 典型場景 |
@Deprecated | java.lang | 標記 API 已過時,編譯器發出警告 | 舊版方法、欄位、類別 |
@Override | java.lang | 宣告方法覆寫父類別/介面方法,編譯器驗證簽名 | 所有覆寫方法強烈建議加上 |
@SuppressWarnings | java.lang | 壓制編譯器特定警告 | @SuppressWarnings("unchecked")、"rawtypes"、"deprecation" |
標準註解實戰範例
package sz.starbex.bill.annotation;
import java.util.ArrayList;
import java.util.List;
public class StandardAnnotationsDemo {
public static void main(String[] args) {
StandardAnnotationsDemo demo = new StandardAnnotationsDemo();
System.out.println(demo); // 呼叫 toString()
demo.doSomething(); // 過時方法
demo.testSuppressWarnings();
}
@Override
public String toString() {
return "自訂 toString 輸出";
}
@Deprecated
public void doSomething() {
System.out.println("此方法已過時,請改用 newMethod()");
}
@SuppressWarnings("unchecked") // 壓制「未檢查轉型」警告
public void testSuppressWarnings() {
List list = new ArrayList(); // 原始型別 List
list.add("KKKK"); // 型別不安全
// 編譯器不再警告 unchecked
}
}
自訂註解設計範本
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
String value() default "";
int priority() default 0;
String[] tags() default {};
}
運行時讀取註解(反射)
public class AnnotationReader {
public static void main(String[] args) throws Exception {
Class clazz = StandardAnnotationsDemo.class;
// 類別層級
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation ann = clazz.getAnnotation(MyAnnotation.class);
System.out.println("類別註解: " + ann.value() + ", priority=" + ann.priority());
}
// 方法層級
for (var method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation ann = method.getAnnotation(MyAnnotation.class);
System.out.println("方法 " + method.getName() + ": " + ann.value());
}
}
}
}
進階:註解處理器(Annotation Processor)
- 編譯期掃描註解、產生程式碼/資源/錯誤訊息。
- 實作
javax.annotation.processing.Processor,註冊於 META-INF/services/javax.annotation.processing.Processor。
- 經典應用:Lombok、MapStruct、Dagger、Room、ButterKnife(舊)。
- 啟動方式:
javac -processor com.example.MyProcessor ... 或 IDE 自動偵測。
最佳實務
- @Target 盡可能精確限定,避免濫用。
- @Retention(RUNTIME) 僅在需反射讀取時使用;純編譯期驗證用
SOURCE,減少 .class 體積。
- 屬性命名慣例:單一屬性用
value(),多屬性用語意化名稱。
- 提供
default 值提升易用性。
- 文件化註解語意、預期用法、處理器行為。