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

Java 註解完整指南:從基礎到自訂註解處理器

     編輯:Java 相關知識

Java 註解深度解析

Java 註解自 JDK 5.0 (2004) 引入以來,已成為現代 Java 開發的基石。Spring、Hibernate、JUnit、MyBatis 等主流框架大量依賴註解實現聲明式配置、依賴注入、事務管理、測試標記等功能。本文系統梳理註解核心概念、內建註解、元註解、自訂註解定義與實務應用模式。

註解核心概念

  • 本質:繼承自 java.lang.annotation.Annotation 的介面,編譯期/運行期可透過反射讀取
  • 作用目標:套用於套件、類別、介面、方法、建構子、欄位、參數、區域變數、型別使用、模組等程式元素
  • 生命週期:SOURCE (僅原始碼) → CLASS (編譯期,預設) → RUNTIME (運行期可反射讀取)
  • 核心優勢:取代 XML 配置、編譯期檢查、程式碼文檔化、框架整合、程式碼生成

三種基本註解型態

1. 標記註解 - 無任何元素

// 定義
public @interface ThreadSafe {}

// 使用
@ThreadSafe
public class ImmutablePoint {
    private final int x, y;
    // ...
}

2. 單元素註解 - 僅一個 value 元素

// 定義 (元素名稱必須為 value)
public @interface Priority {
    int value() default 0;
}

// 使用 - 可省略元素名稱
@Priority(10)
public class CriticalTask {}

// 等同於 @Priority(value = 10)

3. 完整值註解 - 多個元素

// 定義
public @interface AuditLog {
    String operation();
    String module() default "SYSTEM";
    boolean async() default true;
    int[] relatedIds() default {};
}

// 使用 - 必須指定所有無預設值的元素
@AuditLog(
    operation = "DELETE_USER",
    module = "USER_MGMT",
    async = false,
    relatedIds = {1001, 1002}
)
public void deleteUser(Long userId) { ... }

四大元註解 - 註解的註解

元註解用途關鍵屬性
@Target限定註解可套用的程式元素類型ElementType.TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE
@Retention指定註解保留階段RetentionPolicy.SOURCE, CLASS, RUNTIME
@Documented標記此註解應包含在 Javadoc 中無
@Inherited允許子類別繼承父類別的此註解 (僅限 TYPE 目標)無
@Repeatable允許同一元素重複套用同一註解 (Java 8+)value = 容器註解類別
@Native標示常數可能被原生程式碼引用 (Java 8+)無

自訂註解完整範例

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiEndpoint {
    String path();
    RequestMethod method() default RequestMethod.GET;
    String description() default "";
    int version() default 1;
    boolean deprecated() default false;
    String[] tags() default {};
}

public enum RequestMethod { GET, POST, PUT, DELETE, PATCH }

// 使用範例
@ApiEndpoint(
    path = "/users/{id}",
    method = RequestMethod.GET,
    description = "取得使用者資料",
    version = 2,
    tags = {"user", "query"}
)
public class UserController {
    @ApiEndpoint(path = "/users", method = RequestMethod.POST, description = "建立使用者")
    public Response createUser(Request request) { ... }
}

運行期註解處理 - 反射讀取

public class AnnotationProcessor {
    public static void scanEndpoints(Class clazz) {
        // 類別層級註解
        if (clazz.isAnnotationPresent(ApiEndpoint.class)) {
            ApiEndpoint ep = clazz.getAnnotation(ApiEndpoint.class);
            System.out.println("Controller: " + ep.path() + " v" + ep.version());
        }

        // 方法層級註解
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(ApiEndpoint.class)) {
                ApiEndpoint ep = method.getAnnotation(ApiEndpoint.class);
                System.out.printf("  %s %s - %s%n", 
                    ep.method(), ep.path(), ep.description());
            }
        }
    }
}

編譯期註解處理器 (Annotation Processor)

實作 javax.annotation.processing.Processor 介面,可在編譯期掃描註解並生成程式碼、資源檔、配置檔等。常見應用:

  • Lombok (@Getter/@Setter/@Builder 產生樣板碼)
  • MapStruct (介面轉實作類別)
  • Room Database (DAO 實作生成)
  • Dagger/Hilt (依賴注入程式碼生成)
@SupportedAnnotationTypes("com.example.ApiEndpoint")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class ApiEndpointProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set annotations, RoundEnvironment env) {
        for (Element element : env.getElementsAnnotatedWith(ApiEndpoint.class)) {
            // 生成 OpenAPI/Swagger 文檔、路由註冊碼、測試樁等
            generateRouterCode(element);
        }
        return true;
    }
}

Java 8+ 註解新特性

  • 型別註解:@NonNull String[] arr、List<@NonNull String>、(@NonNull String) -> ... (需 @Target(TYPE_USE))
  • 重複註解:@Repeatable(Schedules.class) 允許 @Schedule(...) 寫多次
  • 參數名稱保留:編譯參數 -parameters 讓反射可讀取方法參數名

實務最佳實踐

  1. 明確 @Retention:運行期需反射讀取用 RUNTIME,編譯期處理用 CLASS,僅原始碼檢查用 SOURCE
  2. 限定 @Target:避免註解被誤用在不支援的元素上
  3. 提供合理預設值:減少使用者樣板碼
  4. 文檔化:加上 @Documented 讓 Javadoc 包含註解說明
  5. 避免濫用:簡單配置用屬性檔/環境變數,複雜邏輯用程式碼,註解專注於聲明式元資料
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved