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

Java 註解與元註解深度解析:從標準註解到自定義處理器

     編輯:Java 相關知識

前言:為什麼需要註解?

註解提供了「聲明式元資料」能力,讓工具/框架在編譯期、類載入期、運行期讀取程式碼附加語義,實現代碼生成 (Lombok, MapStruct)、配置替代 XML (Spring, JPA)、靜態分析 (Checker Framework)、運行時行為注入 (AOP, 驗證)。JDK 5 引入統一註解機制,核心包含:定義語法、聲明語法、反射讀取 API、編譯器插件 (Annotation Processor)。

一、 核心概念:註解 vs 元註解

  • 註解:修飾程式元素 (類、方法、欄位、參數、區域變數、套件、類型使用) 的標記。
  • 元註解:修飾「註解定義」的註解,定義註解的生命週期、作用目標、繼承性、文檔化。

二、 四大標準元註解詳解

元註解作用關鍵屬性值說明
@Retention生命週期SOURCE (編譯期丟棄)、CLASS (class 檔保留,VM 忽略,預設)、RUNTIME (運行期反射可讀)需反射讀取必須用 RUNTIME
@Target作用目標TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNOTATION_TYPE、PACKAGE、TYPE_PARAMETER、TYPE_USE (JDK8+)可組合,如 {METHOD, FIELD}
@Inherited繼承性無屬性被標註的註解類型可被子類繼承 (僅限 TYPE 目標)
@Documented文檔化無屬性標註此元註解的註解會出現在 Javadoc 中
@Repeatable (JDK8+)可重複value = 容器註解類型允許同一位置多次使用同一註解
@Native (JDK8+)原生常量無屬性提示註解值可能被原生代碼 (JNI) 讀取

三、 定義自訂註解:語法與元素


@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuditLog {
    String value() default "";           // 單一元素慣用 value()
    String operator() default "system";  // 一般元素
    int level() default 1;               // 基本型別
    Severity severity() default Severity.INFO; // 列舉類型
    Class<?>[] relatedEntities() default {};    // 類別陣列
    // 不允許:方法參數、throws 子句、泛型元素 (除 Class)
}

enum Severity { INFO, WARN, ERROR }

使用範例


@AuditLog(value = "用戶登入", operator = "auth-service", severity = Severity.INFO)
public void login(String username) { ... }

@AuditLog("資料刪除") // 省略 value() 名稱
public void delete(long id) { ... }

四、 標準註解速查 (JDK 內建)

註解用途適用階段
@Override編譯期檢查方法確實覆寫父類/介面方法SOURCE
@Deprecated標記不建議使用,編譯器警告RUNTIME
@SuppressWarnings抑制特定編譯器警告SOURCE
@SafeVarargs (JDK7+)標記方法/建構子不執行不可靠的可變參數操作RUNTIME
@FunctionalInterface (JDK8+)標記函數式介面 (單一抽象方法),編譯器驗證RUNTIME

五、 註解處理器 — 編譯期代碼生成核心

實作 javax.annotation.processing.Processor,在編譯期掃描註解、生成新原始檔/資源/類檔。典型應用:

  • Lombok:@Getter/@Setter/@Builder 生成樣板代碼。
  • MapStruct:@Mapper 生成型別安全映射實作。
  • Dagger/Hilt:@Component/@Module 生成依賴注入代碼。
  • Room:@Entity/@Dao 生成 SQLite 操作代碼。

簡易處理器骨架


@SupportedAnnotationTypes("com.example.AuditLog")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class AuditLogProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element elem : roundEnv.getElementsAnnotatedWith(AuditLog.class)) {
            AuditLog ann = elem.getAnnotation(AuditLog.class);
            // 使用 Filer 生成代碼/資源/類
            // processingEnv.getFiler().createSourceFile(...)
        }
        return true; // 聲明已處理
    }
}

註冊:在 META-INF/services/javax.annotation.processing.Processor 列出處理器全限定名。

六、 運行期反射讀取註解


Method method = MyClass.class.getMethod("login", String.class);
if (method.isAnnotationPresent(AuditLog.class)) {
    AuditLog ann = method.getAnnotation(AuditLog.class);
    System.out.println(ann.value() + " | " + ann.severity());
}

// 獲取所有註解 (含元註解)
Annotation[] anns = method.getAnnotations(); // 含繼承
Annotation[] declaredAnns = method.getDeclaredAnnotations(); // 僅本類聲明

七、 實戰設計原則

  1. 職責單一:一個註解只表達一個語義維度 (如 @Transactional 只管事務邊界)。
  2. 預設值合理:減少使用者樣板代碼。
  3. 最小化 @Target:僅允許必要位置,防止濫用。
  4. 文檔化公開 API 註解:加 @Documented 讓 Javadoc 保留。
  5. 避免註解爆炸:超過 5-6 個自訂註解考慮合併或改用介面/基類。

總結

註解是 Java 元編程的基石。掌握「定義→元註解配置→處理器/反射消費」完整鏈路,能讓你從框架使用者進階為框架建設者,構建極具表達力的領域特定語言 (DSL) 於 Java 之上。

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