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

Java 自定義注解完整實戰指南:元注解、定義、使用與反射解析全流程

     編輯:Java 程式設計入門

注解基礎概念

  • 注解(Annotation)是附加在代碼上的元數據,不影響業務邏輯
  • 編譯期、類加載期、運行期三個生命週期階段可被工具處理
  • 核心包:java.lang.annotation

四大元注解詳解

@Retention:保留策略


@Retention(RetentionPolicy.SOURCE)   // 僅源碼保留,編譯器丟棄(如 @Override、@SuppressWarnings)
@Retention(RetentionPolicy.CLASS)    // 編譯入 class,運行時不可見(默認)
@Retention(RetentionPolicy.RUNTIME)  // 運行時可見,反射可獲取(自定義注解常用)

@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+)

可組合:@Target({ElementType.METHOD, ElementType.FIELD})

@Documented:文檔化

標記後,javadoc 會包含該注解信息。

@Inherited:繼承性

子類自動繼承父類的該注解(僅針對 TYPE 級別注解)。

自定義注解定義範例


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface HelloWorld {
    String name() default "";           // 必須有默認值或使用時指定
    int priority() default 1;
    String[] tags() default {};         // 數組類型
}

規則:

  • 修飾符隱式 public abstract
  • 屬性類型:基本類型、String、Class、枚舉、注解、以上類型數組
  • 無參數、無拋出異常、無泛型
  • 默認值用 default,不能為 null

注解使用示例


public class SayHello {
    @HelloWorld(name = "小明", priority = 2, tags = {"greeting", "demo"})
    public void sayHello(String name) {
        System.out.println(name + " say hello world!");
    }
    
    @HelloWorld(name = "默認優先級")
    public void sayHi() { ... }
}

反射解析注解核心 API


public class AnnotationParser {
    public void parse(Class clazz) {
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            
            for (Method method : clazz.getDeclaredMethods()) {
                // 獲取方法上的指定注解
                HelloWorld annotation = method.getAnnotation(HelloWorld.class);
                if (annotation != null) {
                    String name = annotation.name();
                    int priority = annotation.priority();
                    String[] tags = annotation.tags();
                    
                    System.out.printf("方法: %s, name=%s, priority=%d, tags=%s%n",
                        method.getName(), name, priority, Arrays.toString(tags));
                    
                    // 調用方法
                    method.invoke(instance, name);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("解析失敗", e);
        }
    }
    
    public static void main(String[] args) {
        new AnnotationParser().parse(SayHello.class);
    }
}

進階:多注解聚合與繼承


// 容器注解 (Java 8+ @Repeatable)
@Repeatable(HelloWorlds.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HelloWorld { ... }

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HelloWorlds {
    HelloWorld[] value();
}

// 使用
@HelloWorld(name = "A")
@HelloWorld(name = "B")
public void multiAnnotated() { ... }

// 解析
HelloWorlds container = method.getAnnotation(HelloWorlds.class);
if (container != null) {
    for (HelloWorld hw : container.value()) { ... }
}
// 或 Java 8+ 直接獲取數組
HelloWorld[] annos = method.getAnnotationsByType(HelloWorld.class);

最佳實踐檢查清單

  1. 運行期解析必須加 @Retention(RUNTIME)
  2. 明確限定 @Target,避免濫用
  3. 屬性命名遵循駝峰,布爾類型用 enabled() 而非 isEnabled()
  4. 提供合理默認值,減少使用端樣板代碼
  5. 文檖化公共 API 注解(@Documented)
  6. 框架開發時考慮 AnnotationProcessor 編譯期處理,降低運行時開銷
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved