@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
若 @Retention(SOURCE) 或 CLASS,運行時不可反射,需編譯期處理:
// 1. 定義 Processor
@SupportedAnnotationTypes("demo.annotation.ITCastAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class MyProcessor extends AbstractProcessor {
@Override public boolean process(Set extends TypeElement> 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 @Id | RUNTIME (Hibernate) / COMPILE (MyBatis Plus) |
| 參數校驗 | @NotNull @Size @Pattern | RUNTIME (Bean Validation) |
| 依賴注入 | @Autowired @Qualifier @Value | RUNTIME (Spring) |
| 代碼生成 | @Getter @Setter @Builder | SOURCE (Lombok) |
| API 文檔 | @Operation @Parameter @Schema | RUNTIME (SpringDoc/OpenAPI) |
| 編譯期檢查 | @Override @Deprecated @SuppressWarnings | SOURCE (javac 內建) |
註解屬性類型僅支持:
StringClass / Class<?>不支持: 物件、集合、Map、多維數組、null (但可用默認值模擬)。
Java 註解 = 元數據載體 + 編譯期/運行期處理入口。掌握 @Retention(RUNTIME) + 反射 API 可實現框架級功能;掌握 AbstractProcessor 可實現 Lombok/MapStruct 式代碼生成。核心設計原則:註解定義「是什麼」,處理器定義「怎麼做」,二者解耦才能支撐生態繁榮。