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

Java 註解核心:元註解、自定義註解與註解處理器實戰指南

     編輯:Java 程式設計入門

元註解:註解的註解

Java 定義 4 標準元註解(java.lang.annotation 套件),用於描述其他註解的行為:

@Target:註解適用目標

@Target(ElementType.TYPE) // 類、介面、枚舉、註解
@Target(ElementType.FIELD) // 欄位(包含枚舉常數)
@Target(ElementType.METHOD) // 方法
@Target(ElementType.PARAMETER) // 參數
@Target(ElementType.CONSTRUCTOR) // 建構子
@Target(ElementType.LOCAL_VARIABLE) // 區域變數
@Target(ElementType.ANNOTATION_TYPE) // 註解類型
@Target(ElementType.PACKAGE) // 套件
@Target(ElementType.TYPE_PARAMETER) // 型別參數 (Java 8+)
@Target(ElementType.TYPE_USE) // 型別使用 (Java 8+)

@Retention:生命週期策略

策略保留範圍典型用途
RetentionPolicy.SOURCE僅原始碼,編譯器捨棄@Override, @SuppressWarnings, @Generated
RetentionPolicy.CLASSClass 檔案,JVM 不載入(預設)編譯期處理、字節碼掃描
RetentionPolicy.RUNTIME運行時可透過反射獲取框架整合、依賴注入、AOP、序列化

@Documented:文檔化標記

  • 標記註解,無屬性
  • 被標註的註解會出現在 Javadoc 生成的文檔中
  • 公共 API 註解建議加上

@Inherited:繼承性標記

  • 類別繼承時,子類別自動獲得父類別的該註解
  • 僅對類別有效,介面實現、方法覆寫不生效
  • 配合 RUNTIME 保留,反射 API 會遞歸查找父類別

自定義註解語法規範

聲明格式

public @interface AnnotationName {
    // 屬性定義 = 無參方法
    // 預設值用 default
    String value() default "";
    int count() default 0;
    Class<?> clazz() default Object.class;
    Color color() default Color.RED;
    String[] tags() default {};
}

屬性類型限制

  • 8 種基本型別
  • String
  • Class
  • enum
  • 註解類型(支援巢狀)
  • 以上類型的陣列
  • 禁止:物件、集合、泛型、可變型別

存取修飾符

  • 僅允許 public 或 default(包私有)
  • 慣例使用 default(無修飾符)

單屬性慣例

// 單屬性命名為 value,使用時可省略屬性名
@FunctionalInterface
public @interface MyAnnotation {
    String value() default "";
}

// 使用
@MyAnnotation("hello") // 等同於 @MyAnnotation(value="hello")

完整自定義註解範例

1. 表映射註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
    String name() default ""; // 預設類別名
    String schema() default "";
    String catalog() default "";
}

2. 欄位映射註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    String name() default ""; // 預設欄位名
    boolean nullable() default true;
    boolean unique() default false;
    int length() default 255;
    String columnDefinition() default "";
}

3. 實體類別使用

註解處理器:讓註解發揮作用

運行時反射處理(最常見)

public class AnnotationProcessor {
    public void processTable(Object entity) {
        Class<?> clazz = entity.getClass();
        
        // 1. 獲取類別註解
        Table table = clazz.getAnnotation(Table.class);
        String tableName = table != null && !table.name().isEmpty() 
            ? table.name() : clazz.getSimpleName();
        
        // 2. 掃描欄位註解
        List columns = new ArrayList<>();
        List values = new ArrayList<>();
        
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true); // 存取私有欄位
            
            Column column = field.getAnnotation(Column.class);
            if (column == null) continue; // 無註解跳過
            
            String colName = column.name().isEmpty() ? field.getName() : column.name();
            Object value;
            try {
                value = field.get(entity);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            
            columns.add(colName);
            values.add(value != null ? "'" + value + "'" : "NULL");
        }
        
        // 3. 生成 SQL
        String sql = String.format("INSERT INTO %s (%s) VALUES (%s)",
            tableName, String.join(", ", columns), String.join(", ", values));
        System.out.println(sql);
    }
}

編譯期註解處理(APT,進階)

  • 實現 javax.annotation.processing.Processor
  • 註冊 META-INF/services/javax.annotation.processing.Processor
  • 編譯期生成代碼(如 Lombok、MapStruct、Dagger、Room)
  • 不影響運行時效能,但開發複雜度高

內建註解最佳實踐

註解用途最佳實踐
@Override方法覆寫檢查所有覆寫方法強制加上,防止拼寫錯誤
@Deprecated標記過時配合 Javadoc @deprecated 說明替代方案
@SuppressWarnings抑制編譯警告範圍最小化,僅加在具體語句/方法,避免類別級
@SafeVarargs可變參數堆污染抑制僅用於確認安全的 final/static 方法
@FunctionalInterface函數式介面標記所有 SAM 介面加上,編譯器強制檢查

常見陷阱與避坑指南

陷阱後果解決
@Retention 預設為 CLASS運行時反射獲取不到框架整合註解必須显式 @Retention(RUNTIME)
@Target 缺失可用於所有位置,語義模糊明確限定適用範圍
屬性用物件/集合編譯錯誤轉為陣列、字串、枚舉、Class
註解繼承誤區介面實現/方法覆寫不繼承 @Inherited理解僅類別繼承生效
預設值不一致註解處理器邏輯複雜統一預設值語義,文檔化說明

總結

註解是 Java 元程式設計的核心。掌握元註解配置、自定義語法規範、反射處理器實現,能構建類型安全、可讀性強、框架友好的 API。運行時反射適合業務邏輯處理,編譯期 APT 適合代碼生成,兩者互補,共同構建現代 Java 生態系統。

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