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

Java 註解原理深度解析:從定義、元註解到運行時反射獲取完整實戰

     編輯:Java 綜合教學

註解本質:特殊的接口

@interface 編譯後生成繼承 java.lang.annotation.Annotation 的接口。註解實例由 JVM 在類加載時動態生成的代理類實現(如 $$Proxy1),屬性值存儲在 class 文件 RuntimeVisibleAnnotations 屬性表中。

元註解:註解的註解

元註解作用關鍵取值
@Target限制註解可標註位置ElementType.TYPE/METHOD/FIELD/PARAMETER/ANNOTATION_TYPE/PACKAGE/LOCAL_VARIABLE/TYPE_PARAMETER/TYPE_USE
@Retention聲明生命周期SOURCE (源碼) / CLASS (字節碼,默認) / RUNTIME (運行時可反射)
@Documented納入 Javadoc無參數
@Inherited子類繼承父類註解僅對 @Target(TYPE) 生效
@Repeatable同一位置可重複標註Java 8+,需配合容器註解
@Native常量字段可被原生代碼引用Java 8+,極少用

自定義註解完整範例

package demo.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)           // 關鍵:運行時可反射
@Documented
public @interface ITCastAnnotation {
    String color() default "blue";            // 基礎類型屬性
    String value();                           // 特殊屬性:單屬性時可省略鍵名
    int[] arrayAttr() default {1,2,3};        // 數組屬性
    TrafficLamp lamp() default TrafficLamp.RED; // 枚舉屬性
    MetaAnnotation annotationAttr() default @MetaAnnotation("lhm"); // 註解嵌套
    Class clazz() default String.class;    // Class 類型屬性
}

// 配套枚舉
enum TrafficLamp {
    RED(400) { public TrafficLamp next() { return GREEN; } },
    GREEN(200) { public TrafficLamp next() { return YELLOW; } },
    YELLOW(10)  { public TrafficLamp next() { return RED; } };
    private final int duration;
    TrafficLamp(int d) { duration = d; }
    public abstract TrafficLamp next();
    public int duration() { return duration; }
}

// 元註解:作為屬性類型被嵌套
@Retention(RetentionPolicy.RUNTIME)
@interface MetaAnnotation { String value(); }

運行時反射解析註解

@ITCastAnnotation(
    annotationAttr = @MetaAnnotation("fxx"),
    value = "111",
    arrayAttr = {2,3,4}
)
public class AnnotationTest {
    public static void main(String[] args) {
        Class clazz = AnnotationTest.class;
        if (clazz.isAnnotationPresent(ITCastAnnotation.class)) {
            ITCastAnnotation ann = clazz.getAnnotation(ITCastAnnotation.class);
            System.out.println("value: " + ann.value());
            System.out.println("color: " + ann.color());
            System.out.print("arrayAttr: "); Arrays.stream(ann.arrayAttr()).forEach(i -> System.out.print(i + " "));
            System.out.println();
            System.out.println("lamp.next: " + ann.lamp().next());
            System.out.println("nested annotation: " + ann.annotationAttr().value());
            System.out.println("clazz: " + ann.clazz());
        }
    }
}

輸出:

value: 111
color: blue
arrayAttr: 2 3 4
lamp.next: GREEN
nested annotation: fxx
clazz: class java.lang.String

編譯時處理:Annotation Processor (APT)

若 @Retention(SOURCE) 或 CLASS,運行時不可反射,需編譯期處理:

// 1. 定義 Processor
@SupportedAnnotationTypes("demo.annotation.ITCastAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class MyProcessor extends AbstractProcessor {
    @Override public boolean process(Set annotations, RoundEnvironment env) {
        for (Element e : env.getElementsAnnotatedWith(ITCastAnnotation.class)) {
            // 生成代碼、寫文件、報錯警告
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "處理: " + e);
        }
        return true;
    }
}

// 2. META-INF/services/javax.annotation.processing.Processor
// 內容: demo.annotation.MyProcessor

// 3. 編譯時自動觸發: javac -processorpath ... 或 IDE 開啟 Annotation Processing

實戰應用場景

場景註解示例處理階段
ORM 映射@Entity @Table @Column @IdRUNTIME (Hibernate) / COMPILE (MyBatis Plus)
參數校驗@NotNull @Size @PatternRUNTIME (Bean Validation)
依賴注入@Autowired @Qualifier @ValueRUNTIME (Spring)
代碼生成@Getter @Setter @BuilderSOURCE (Lombok)
API 文檔@Operation @Parameter @SchemaRUNTIME (SpringDoc/OpenAPI)
編譯期檢查@Override @Deprecated @SuppressWarningsSOURCE (javac 內建)

進階:註解屬性值的類型限制

註解屬性類型僅支持:

  • 基本類型 (int, long, boolean 等)
  • String
  • Class / Class<?>
  • 枚舉類型
  • 註解類型 (嵌套)
  • 以上類型的一維數組

不支持: 物件、集合、Map、多維數組、null (但可用默認值模擬)。

總結

Java 註解 = 元數據載體 + 編譯期/運行期處理入口。掌握 @Retention(RUNTIME) + 反射 API 可實現框架級功能;掌握 AbstractProcessor 可實現 Lombok/MapStruct 式代碼生成。核心設計原則:註解定義「是什麼」,處理器定義「怎麼做」,二者解耦才能支撐生態繁榮。

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