Java 註解(Annotation)本質是「描述代碼的代碼」,屬於一種修飾符,與 public、static、transient 同級。不同於註釋僅在源碼階段給人看,註解能被編譯器、工具、運行時 JVM 讀取並觸發行為。
| 特性 | 註釋 (// /* */) | Javadoc (/** */) | 註解 (@Annotation) |
|---|---|---|---|
| 作用階段 | 僅源碼 | 源碼→HTML文檔 | 源碼、編譯期、運行時 |
| 可被程序讀取 | 否 | 僅文檔工具 | 是(反射/APT) |
| 可攜帶結構化數據 | 否 | 否 | 是(屬性值) |
| 可觸發代碼生成/邏輯 | 否 | 否 | 是 |
@Target(ElementType.METHOD)
public @interface MyAnnotation {}
ElementType 枚舉值:
TYPE:類/接口/枚舉/註解類型FIELD:屬性/枚舉常量METHOD:方法PARAMETER:參數CONSTRUCTOR:構造器LOCAL_VARIABLE:局部變量ANNOTATION_TYPE:註解類型PACKAGE:包@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
三種策略:
SOURCE:編譯期丟棄(如 @Override、@SuppressWarnings)CLASS:編入 .class,運行時不可見(默認值)RUNTIME:運行時可通過反射讀取(自定義註解常用)被此元註解修飾的註解,生成 API 文檔時會保留。
若註解類型被 @Inherited 修飾,子類未顯式聲明該註解時,會自動向父類查找。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
常用抑制值:
deprecation:使用過時 APIunchecked:泛型未檢查轉換serial:可序列化類缺少 serialVersionUIDall:抑制所有@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
String author() default "unknown";
String date();
int version() default 1;
}
規則:
@interface 關鍵字default 指定默認值public class AnnotationTest {
@MethodInfo(author="zhangsan", date="20240115")
public static void main(String[] args) {
System.out.println("Using custom annotation...");
}
}
註解本身是被動的元數據,必須由框架/工具主動解析才能產生作用。
@Retention(CLASS) 註解AbstractProcessor,重寫 process()@Retention(RUNTIME) 註解java.lang.reflect.AnnotatedElementpublic class AnnotationParser {
public static void main(String[] args) throws Exception {
Class<?> clazz = AnnotationTest.class;
for (Method method : clazz.getDeclaredMethods()) {
MethodInfo info = method.getAnnotation(MethodInfo.class);
if (info != null) {
System.out.println("Method: " + method.getName());
System.out.println("Author: " + info.author());
System.out.println("Date: " + info.date());
System.out.println("Ver: " + info.version());
}
}
}
}
@Inherited 才能被子類繼承;方法註解不支持繼承掌握註解機制,是理解 Spring、Hibernate、MyBatis 等主流框架核心原理的鑰匙,也是構建優雅 DSL、自動化代碼生成工具的基石。