Java 1.5 引入註解機制,將元數據直接嵌入源碼,並通過編譯器保留至字節碼,配合反射實現運行時檢測,極大豐富了框架開發與代碼檢查能力。本文系統梳理內置註解、元註解、自定義註解定義與解析全流程。
| 註解 | 作用 | 版本 |
|---|---|---|
@Override | 檢查方法是否正確覆寫父類/接口方法,否則編譯報錯 | 1.5 |
@Deprecated | 標記棄用 API,使用時編譯器發出警告 | 1.5 |
@SuppressWarnings | 抑制特定編譯器警告 | 1.5 |
@SafeVarargs | 抑制泛型可變參數堆污染警告 | 1.7 |
@FunctionalInterface | 標記函數式接口,編譯器驗證只有一個抽象方法 | 1.8 |
元註解用於定義自定義註解的行為特徵:
SOURCE:僅源碼保留,編譯丟棄CLASS(默認):編譯進 class,類加載時忽略RUNTIME:運行時可通過反射獲取@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ClassInfo {
String author() default "Wang";
String date();
String comments();
}
關鍵規則:
@interface 關鮮字,隱式繼承 java.lang.annotation.Annotationdefault 指定默認值// 作用於方法
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodInfo {
String description() default "No Description";
String date();
}
// 作用於字段
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldInfo {
String type();
String name();
}
@ClassInfo(author = "wang", date = "2024/01/15", comments = "示例類")
public class AnnotationDemo {
@FieldInfo(type = "public", name = "firstField")
public int firstField;
@FieldInfo(type = "private", name = "secondField")
private String secondField;
@MethodInfo(description = "核心業務方法", date = "2024/01/15")
public void firstMethod(String value) { /* ... */ }
@MethodInfo(description = "輔助方法", date = "2024/01/15")
private void secondMethod() { /* ... */ }
}
注意:無默認值的參數必須顯式賦值,否則編譯報錯。
前提:註解需標註 @Retention(RetentionPolicy.RUNTIME)。
public class AnnotationParser {
public static void parse(Class> clazz) {
// 1. 類級註解
if (clazz.isAnnotationPresent(ClassInfo.class)) {
ClassInfo ci = clazz.getAnnotation(ClassInfo.class);
System.out.printf("類註解:%s %s %s%n", ci.author(), ci.date(), ci.comments());
}
// 2. 字段級註解
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(FieldInfo.class)) {
FieldInfo fi = field.getAnnotation(FieldInfo.class);
System.out.printf("字段 %s:%s %s%n", field.getName(), fi.type(), fi.name());
}
}
// 3. 方法級註解
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(MethodInfo.class)) {
MethodInfo mi = method.getAnnotation(MethodInfo.class);
System.out.printf("方法 %s:%s %s%n", method.getName(), mi.description(), mi.date());
}
}
}
}
RUNTIME;編譯期檢查(如 Lombok)用 SOURCE;字節碼分析工具用 CLASS。ElementType.TYPE 覆蓋所有類型,按需最小化範圍。@Inherited 僅對類有效,不適用於接口、方法、字段。註解是 Java 元數據編程的基石,從內置語義約束到自定義領域模型,配合反射實現「聲明式編程」。掌握元註解組合、參數約束、反射解析全鏈路,是進階框架開發與源碼閱讀的必備技能。