首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 自訂註解入門實戰:元註解詳解與註解處理器雛形

     編輯:Java 程式設計入門

元註解:註解的註解

定義於 java.lang.annotation,用於約束自訂註解的使用目標、生命週期、文件化、繼承等語義。

四大核心元註解

元註解作用關鍵屬性值
@Target限定註解可標註的程式元素ElementType:
TYPE(類/介面/enum/註解)
FIELD(欄位/列舉常數)
METHOD(方法)
PARAMETER(參數)
CONSTRUCTOR(建構子)
LOCAL_VARIABLE(區域變數)
PACKAGE(套件聲明)
@Retention定義註解保留到哪個階段RetentionPolicy:
SOURCE:源碼,編譯器捨棄
CLASS:.class 檔,JVM 載入但不可反射(預設)
RUNTIME:執行期可透過反射讀取 (框架常用)
@Documented標示此註解應被 javadoc 納入 API 文件標記註解,無屬性
@Inherited允許子類別繼承父類別的此註解(僅限 TYPE)標記註解;配合 RUNTIME 反射時會向上查找父類別

自訂註解語法規範


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";  // 單屬性慣命名 value()
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    enum Color { RED, GREEN, BLUE }
    Color fruitColor() default Color.GREEN;
}

屬性定義規則

  • 以無參數方法形式宣告,方法名即屬性名,回傳型別即屬性型別。
  • 允許型別:8 大基本型別、String、Class、enum、Annotation、及其陣列。
  • 修飾符僅能 public 或預設(package-private)。
  • 可用 default 指定預設值(編譯期常數)。
  • 單屬性註解慣命名為 value(),使用時可省略屬性名:@FruitName("Apple")。

套用自訂註解


public class Apple {
    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor = FruitColor.Color.RED)
    private String appleColor;

    // getter/setter 略
}

註解處理器雛形:執行期反射讀取


import java.lang.reflect.Field;

public class FruitInfoScanner {
    public static void scan(Object obj) {
        Class clazz = obj.getClass();
        System.out.println("掃描類別:" + clazz.getSimpleName());

        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);

            // 讀取 @FruitName
            FruitName nameAnno = field.getAnnotation(FruitName.class);
            if (nameAnno != null) {
                System.out.println("  欄位:" + field.getName() + " → 水果名稱:" + nameAnno.value());
            }

            // 讀取 @FruitColor
            FruitColor colorAnno = field.getAnnotation(FruitColor.class);
            if (colorAnno != null) {
                System.out.println("  欄位:" + field.getName() + " → 顏色:" + colorAnno.fruitColor());
            }
        }
    }

    public static void main(String[] args) {
        scan(new Apple());
    }
}

輸出結果

掃描類別:Apple
  欄位:appleName → 水果名稱:Apple
  欄位:appleColor → 顏色:RED

進階:編譯期註解處理 (APT) 入門

若需在編譯期掃描註解並生成新原始碼/資源(如 Lombok、MapStruct、Dagger),需實作 javax.annotation.processing.Processor:

  1. 建立 META-INF/services/javax.annotation.processing.Processor 檔案,內容為處理器全類別名。
  2. 處理器繼承 AbstractProcessor,覆寫 process(Set<? extends TypeElement>, RoundEnvironment)。
  3. 使用 ProcessingEnvironment 提供的 Filer 生成檔案,Messager 輸出編譯訊息。
  4. 編譯器啟動時自動發現並執行處理器。

最佳實踐檢查清單

項目建議
@Target務必精確限定,避免濫用於不相關元素
@Retention反射讀取用 RUNTIME;原始碼工具用 SOURCE;預設 CLASS 多無實際用途
屬性命名單屬性用 value();多屬性用語意化名稱(fruitColor、tableName)
預設值盡量提供合理預設,減少使用者樣板碼
文件化對外 API 註解加 @Documented,納入 javadoc
繼承類別層級註解需子類可見時加 @Inherited

總結

自訂註解 = 語義標記 + 元註解約束 + 處理器邏輯。
RUNTIME + 反射 適合輕量級框架整合、執行期配置驗證。
SOURCE + APT 適合生成代碼、編譯期約束檢查、零執行期開銷。
善用兩者分工,打造類型安全、可驗證、自文件化的開發體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved