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

JDK 5 註解機制全解析:從標準註解到自定義註解與運行時反射應用

     編輯:J2SE

註解演進:從 Javadoc 標簽到語言級元數據

JDK 1.0:@param @return @see 等 Javadoc 標簽,僅供文檔生成。
JDK 5.0:引入 Annotation (註解) 作為語言內置語法,保留至運行時,支援編譯期檢查、代碼生成、運行時反射驅動框架邏輯。

元註解:定義註解的註解

元註解作用關鍵屬性
@Retention生命週期策略SOURCE (源碼丟棄) / CLASS (編譯保留,默認) / RUNTIME (運行時可反射)
@Target作用目標類型TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE
@Documented納入 Javadoc 生成無
@Inherited允許子類繼承父類類級註解僅對 @Target(TYPE) 有效
@Repeatable (JDK 8)同一位置可重複聲明value() 指向容器註解

JDK 5 內置標準註解

@Override 實戰防錯示例


public class Parent { public void foo() { System.out.println("Parent"); } }
public class Child extends Parent {
    @Override
    public void fob() { // 拼寫錯誤:應為 foo
        System.out.println("Child");
    }
}
// 編譯錯誤:Child.java:3: method does not override a method from its superclass

自定義註解:定義與使用

1. 定義註解類型


package com.example.anno;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)  // 關鍵:運行時可反射獲取
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface MyTag {
    String name() default "unknown";
    int    age()  default 0;
    String[] tags() default {};      // 數組屬性
}

2. 使用註解


@MyTag(name = "UserService", age = 1, tags = {"core", "biz"})
public class UserService {
    @MyTag(name = "saveUser", age = 2)
    public void save(User u) { /* ... */ }
}

3. 運行時反射解析


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationParser {
    public static void parse(Class clazz) {
        // 類級註解
        if (clazz.isAnnotationPresent(MyTag.class)) {
            MyTag tag = clazz.getAnnotation(MyTag.class);
            System.out.printf("Class %s: name=%s, age=%d, tags=%s%n",
                clazz.getSimpleName(), tag.name(), tag.age(), Arrays.toString(tag.tags()));
        }
        // 方法級註解
        for (Method m : clazz.getDeclaredMethods()) {
            if (m.isAnnotationPresent(MyTag.class)) {
                MyTag tag = m.getAnnotation(MyTag.class);
                System.out.printf("  Method %s: name=%s, age=%d%n",
                    m.getName(), tag.name(), tag.age());
            }
        }
    }

    public static void main(String[] args) {
        parse(UserService.class);
    }
}
// 輸出:
// Class UserService: name=UserService, age=1, tags=[core, biz]
//   Method save: name=saveUser, age=2

註解屬性類型限制

僅支援:基本類型、String、Class、enum、註解類型、以上類型的一維數組。不支援泛型、嵌套對象、集合。

進階應用模式

  1. 編譯期處理 (APT/Annotation Processor):實現 javax.annotation.processing.Processor,編譯階段掃描註解生成代碼/配置/資源 (如 Lombok、MapStruct、Dagger)。
  2. 運行時框架驅動:Spring @Autowired/@Transactional、JPA @Entity/@Column、JAX-RS @Path/@GET,容器啟動掃描註解構建 Bean 定義/路由表/ORM 映射。
  3. 測試框架:JUnit @Test/@BeforeEach、TestNG @DataProvider,運行器反射發現並執行。
  4. 代碼質量/文檔:SpotBugs @SuppressFBWarnings、Swagger @ApiOperation、自定義 @Reviewed 追蹤代碼審查。

最佳實踐檢查清單

  • [ ] 明確 @Retention(RUNTIME) 需求:僅文檔/編譯期用 CLASS,運行時反射必須 RUNTIME。
  • [ ] 最小化 @Target 範圍:防止濫用於不相關元素。
  • [ ] 提供合理 default 值:減少使用者樣板代碼。
  • [ ] 屬性命名遵循 JavaBean 慣例:小寫駝峰,布爾型用 enabled() 而非 isEnabled()。
  • [ ] 註解類型命名以 @Interface 結尾區分普通接口 (可選約定)。
  • [ ] 文檔註解同步:@Documented + 完整 Javadoc,IDE 懸停提示友好。

結語

JDK 5 註解機制將元數據從「文檔註釋」昇華為「可執行元數據」,奠定了現代 Java 框架 (Spring、Hibernate、JUnit、MyBatis…) 聲明式編程的基石。掌握標準註解防錯、自定義註解設計、反射解析與 APT 編譯期處理四大維度,是從 API 使用者進階為框架構建者的關鍵門檻。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
註解目標語義編譯器行為
@OverrideMETHOD聲明覆寫父類/接口方法若父類無此方法 → 編譯報錯,防止拼寫錯誤
@Deprecated所有標記過時,不建議使用使用處發出警告
@SuppressWarnings所有抑制特定編譯警告value() 指定警告鍵 (unchecked, deprecation, rawtypes...)