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

Java 註解完整指南:從內建註解到自定義註解與反射解析實戰

     編輯:Java 相關知識

前言:註解——代碼中的元數據革命

Java 5 引入註解機制,徹底改變了框架開發模式。Spring、Hibernate、JAX-RS 等主流框架大量採用註解替代繁瑣的 XML 配置,實現「配置即代碼」。本文系統講解註解基礎、元註解詳解、自定義註解實戰、內建註解應用,並演示反射解析註解的完整流程。

一、註解基礎與元註解

1. 定義註解語法

使用 @interface 關鍵字,方法即屬性,支援預設值:

@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
    String author() default "Pankaj";
    String date();
    int revision() default 1;
    String comments();
}

2. 四大元註解詳解

元註解作用關鍵屬性
@Retention聲明生命週期SOURCE(源碼)、CLASS(編譯期,預設)、RUNTIME(運行期,反射必需)
@Target限制標註位置TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, MODULE (Java 9+)
@Documented納入 Javadoc標註的元素將出現在生成的 API 文檔中
@Inherited允許子類繼承僅對 @Target(TYPE) 的類級註解有效

限制規則:註解屬性類型僅限基本型、String、Enum、Class、註解及其陣列;不接受參數;無拋出異常聲明。

二、Java 內建註解

註解用途保留策略
@Override標示覆寫父類方法,編譯器驗證簽名一致性SOURCE
@Deprecated標示不建議使用,Javadoc 會標記,建議說明替代方案RUNTIME
@SuppressWarnings抑制特定編譯警告(如 unchecked, deprecation)SOURCE
@SafeVarargsJava 7+,抑制泛型可變參數堆污染警告RUNTIME
@FunctionalInterfaceJava 8+,標示函數式介面,編譯器強制單一抽象方法RUNTIME

三、自定義註解實戰範例

public class AnnotationExample {
    @Override
    @MethodInfo(author = "Pankaj", comments = "Main method", date = "Nov 17 2012", revision = 1)
    public String toString() { return "Overriden toString method"; }

    @Deprecated
    @MethodInfo(comments = "deprecated method", date = "Nov 17 2012")
    public static void oldMethod() { System.out.println("old method, don't use it."); }

    @SuppressWarnings({ "unchecked", "deprecation" })
    @MethodInfo(author = "Pankaj", comments = "Main method", date = "Nov 17 2012", revision = 10)
    public static void genericsTest() throws FileNotFoundException {
        List l = new ArrayList(); l.add("abc"); oldMethod();
    }
}

四、反射解析註解核心 API

前提:註解必須標註 @Retention(RetentionPolicy.RUNTIME)。

public class AnnotationParsing {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.journaldev.annotations.AnnotationExample");
        for (Method method : clazz.getDeclaredMethods()) {
            // 1. 檢查是否存在特定註解
            if (method.isAnnotationPresent(MethodInfo.class)) {
                // 2. 獲取所有註解(包含內建)
                for (Annotation anno : method.getDeclaredAnnotations()) {
                    System.out.println("Annotation in Method '" + method + "' : " + anno);
                }
                // 3. 獲取指定註解實例,訪問屬性值
                MethodInfo methodAnno = method.getAnnotation(MethodInfo.class);
                if (methodAnno.revision() == 1) {
                    System.out.println("Method with revision no 1 = " + method);
                }
            }
        }
    }
}

關鍵反射方法:

  • isAnnotationPresent(Class):快速判斷
  • getAnnotation(Class):獲取單個註解實例(含繼承)
  • getDeclaredAnnotations():獲取直接聲明的所有註解(不含繼承)
  • getAnnotations():獲取所有註解(含繼承)

五、進階應用場景

  1. 框架級應用:JAX-RS @Path, @GET 映射 REST 端點;Spring @Autowired, @Transactional 驅動 IOC/AOP;JPA @Entity, @Column 定義映射。
  2. 編譯時處理:Lombok、MapStruct、Dagger 使用 Annotation Processor (JSR 269) 在編譯期生成代碼,零運行時開銷。
  3. 測試框架:JUnit @Test, @BeforeEach 控制測試生命週期。
  4. 代碼品質:自定義 @CodeReview, @Todo 配合靜態分析工具追蹤技術債。

六、最佳實踐與避坑指南

  • 保留策略選擇:運行期解析必用 RUNTIME;編譯期處理用 SOURCE;僅文檔用 CLASS(預設)。
  • Target 精確限定:避免濫用,如方法級註解勿標在類上。
  • 屬性預設值:善用 default 減少使用端樣板代碼。
  • 避免註解爆炸:單類註解過多影響可讀性,考慮合併為組合註解或改用配置類。
  • 繼承陷阱:@Inherited 僅對類級註解生效,方法/欄位註解不會被子類繼承。

總結

註解是 Java 元編程的基石,從簡單的編譯器輔助到複雜的框架契約,掌握「定義-保留-目標-解析」全鏈路,能讓你深度理解主流框架運作原理,並具備開發領域專用框架的能力。記住:好的註解設計應該像標準庫一樣直觀、自描述、且有明確的語義契約。

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