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

Java 註解核心機制深度解析:定義、元註解、保留策略與反射獲取實戰

     編輯:Java 綜合教學

Java 註解核心機制深度解析:定義、元註解、保留策略與反射獲取實戰

註解 是 Java 5 引入的元數據機制,讓代碼「自我描述」,成為 Spring、Hibernate、MyBatis、JUnit 等框架實現聲明式編程的基石。本文系統講解註解定義語法、四大元註解、保留策略、目標範圍、屬性默認值、繼承規則,並通過反射實戰演示運行時解析。

一、 註解基本語法與屬性

// 定義註解:interface 前加 @
public @interface Author {
    String name();           // 必填屬性,無默認值
    int age() default 18;    // 可選屬性,有默認值
    String[] tags() default {}; // 數組屬性
}

// 特殊約定:唯一屬性名為 value,使用時可省略屬性名
public @interface Description {
    String value(); // 使用:@Description("核心業務邏輯")
}

// 使用示例
@Author(name = "張三", age = 25, tags = {"core", "api"})
@Description("用戶服務實現")
public class UserService { /* ... */ }

二、 四大元註解:註解的註解

元註解用於修飾註解定義,決定註解「能用在哪、存活多久、是否繼承、是否文檔化」。

元註解作用關鍵屬性/取值默認值
@Target限制註解可應用的程序元素ElementType[] value()
TYPE(類/接口/枚舉)、FIELD(字段)、METHOD(方法)、PARAMETER(參數)、CONSTRUCTOR(構造器)、LOCAL_VARIABLE(局部變量)、ANNOTATION_TYPE(註解)、PACKAGE(包)、TYPE_PARAMETER(類型參數)、TYPE_USE(類型使用)
所有類型均可用
@Retention指定註解生命週期(保留策略)RetentionPolicy value()
SOURCE:源碼級,編譯器丟棄 (如 @Override、@SuppressWarnings)
CLASS:字節碼級,JVM 加載但不保留,**默認值**
RUNTIME:運行時級,反射可見,**框架註解必須設置**
CLASS
@Documented標記註解包含在 Javadoc 中無屬性不文檔化
@Inherited允許子類繼承父類註解無屬性
限制:僅對 類 註解有效;不適用於接口實現;只查詢直接父類,不遞歸。
不繼承

三、 完整註解定義最佳實踐模板

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME) // 框架掃描必須 RUNTIME
@Documented
@Inherited // 僅類層級生效
public @interface ApiOperation {
    String value() default "";           // 接口描述
    String[] tags() default {};          // 分組標籤
    String author() default "unknown";   // 負責人
    int version() default 1;             // 版本號
    boolean deprecated() default false;  // 是否廢棄
}

四、 反射獲取註解實戰

只有 @Retention(RUNTIME) 的註解才能通過反射讀取。

public class AnnotationParser {
    public static void parse(Class clazz) {
        // 1. 類級註解
        if (clazz.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation api = clazz.getAnnotation(ApiOperation.class);
            System.out.printf("Class: %s | Desc: %s | Author: %s | Tags: %s%n",
                clazz.getSimpleName(), api.value(), api.author(), Arrays.toString(api.tags()));
        }

        // 2. 方法級註解(含繼承查找)
        for (Method method : clazz.getDeclaredMethods()) {
            // getAnnotation 不查找父類/接口;需手動遞歸或用 AnnotatedElementUtils (Spring)
            ApiOperation api = method.getAnnotation(ApiOperation.class);
            if (api != null) {
                System.out.printf("  Method: %s | Desc: %s | Deprecated: %s%n",
                    method.getName(), api.value(), api.deprecated());
            }
        }

        // 3. 字段級註解
        for (Field field : clazz.getDeclaredFields()) {
            ApiOperation api = field.getAnnotation(ApiOperation.class);
            if (api != null) {
                System.out.printf("  Field: %s | Desc: %s%n", field.getName(), api.value());
            }
        }
    }

    public static void main(String[] args) {
        parse(UserService.class);
    }
}

五、 常見坑點與避坑指南

  • 忘記 @Retention(RUNTIME):默認 CLASS,反射獲取為 null,**框架級註解必加**。
  • @Target 過度限制:若註解需同時用在類和方法,必須 @Target({TYPE, METHOD})。
  • 數組屬性單元素寫法:@Tag("core") 自動識別為單元素數組;多元素 @Tag({"core", "api"})。
  • @Inherited 失效場景:接口註解不被實現類繼承;父類註解不被孫類繼承(僅直接父類)。Spring 使用 AnnotatedElementUtils.findMergedAnnotation 解決此限制。
  • 註解屬性不可為 null:默認值必須是編譯期常量;無默認值屬性使用時必填。

六、 總結

註解將配置從 XML 解放回代碼,實現「配置即代碼、代碼即文檔」。掌握 @Target 定界、@Retention 決定可見性、@Inherited 規範繼承、反射 API 解析元數據 這四大核心,即可讀懂主流框架源碼、開發自定義框架、構建代碼生成器。下一篇將實戰:基於註解實現輕量級參數校驗框架。

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