註解(Annotation)自 JDK 1.5 引入以來,已成為現代 Java 框架(Spring、Hibernate、MyBatis 等)的核心基礎設施。本文系統講解註解體系、元註解作用、自定義註解定義與反射解析實戰。
三層調用鏈:註解定義 (A) → 業務類使用 (B) → 反射解析器 (C)
// A: 註解定義
@interface A { }
// B: 使用註解
@A class B { }
// C: 反射解析
class C {
void parse() {
if (B.class.isAnnotationPresent(A.class)) {
A a = B.class.getAnnotation(A.class);
// 讀取屬性值...
}
}
}
| 元註解 | 作用 | 關鍵屬性/取值 |
|---|---|---|
@Retention |
聲明註解生命週期 | RetentionPolicy.SOURCE(源碼丟棄)、CLASS(默認,字節碼保留,VM 捨棄)、RUNTIME(運行期保留,可反射讀取) |
@Target |
限定註解適用程序元素 | ElementType.TYPE(類/接口)、METHOD、FIELD、CONSTRUCTOR、PARAMETER、PACKAGE、LOCAL_VARIABLE 等 |
@Documented |
標記註解納入 Javadoc 文檔 | 無屬性,標記即生效,類似 @see、@param |
@Inherited |
允許子類繼承父類註解 | 僅對 @Target(TYPE) 的註解生效 |
public @interface MyAnnotation {
// 1. 參數聲明即方法,無參數、無拋出異常
// 2. 返回類型限制:基本類型、String、Class、enum、Annotation、及其數組
// 3. 可用 default 指定默認值
String name(); // 必填參數
int id() default 0; // 可選參數
Class> clazz(); // Class 類型
ElementType[] targets(); // 枚舉數組
OtherAnnotation meta() default @OtherAnnotation; // 註解嵌套
}
package com.example.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface A {
String name();
int id() default 0;
Class> gid();
}
package com.example.annotation;
import java.util.HashMap;
import java.util.Map;
@A(name = "type", gid = Long.class) // 類級註解
public class B {
@A(name = "field", id = 1, gid = Long.class)
private Integer age;
@A(name = "constructor", id = 2, gid = Long.class)
public B() {}
@A(name = "publicMethod", id = 3, gid = Long.class)
public void publicMethod() {}
@A(name = "protectedMethod", id = 4, gid = Long.class)
protected void protectedMethod() {
Map m = new HashMap<>();
}
@A(name = "privateMethod", id = 5, gid = Long.class)
private void privateMethod() {}
}
package com.example.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class AnnotationParser {
/** 解析類級註解 */
public static void parseTypeAnnotations(Class> clazz) {
for (Annotation ann : clazz.getAnnotations()) {
if (ann instanceof A) {
A a = (A) ann;
System.out.printf("類註解: id=%d, name=%s, gid=%s%n", a.id(), a.name(), a.gid());
}
}
}
/** 解析方法級註解(含私有) */
public static void parseMethodAnnotations(Class> clazz) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(A.class)) {
A a = method.getAnnotation(A.class);
System.out.printf("方法: %s, id=%d, name=%s, gid=%s%n",
method.getName(), a.id(), a.name(), a.gid());
}
}
}
/** 解析構造器註解 */
public static void parseConstructorAnnotations(Class> clazz) {
for (Constructor> ctor : clazz.getDeclaredConstructors()) {
if (ctor.isAnnotationPresent(A.class)) {
A a = ctor.getAnnotation(A.class);
System.out.printf("構造器: %s, id=%d, name=%s, gid=%s%n",
ctor.getName(), a.id(), a.name(), a.gid());
}
}
}
public static void main(String[] args) {
parseTypeAnnotations(B.class);
parseMethodAnnotations(B.class);
parseConstructorAnnotations(B.class);
}
}
類註解: id=0, name=type, gid=class java.lang.Long
方法: publicMethod, id=3, name=publicMethod, gid=class java.lang.Long
方法: protectedMethod, id=4, name=protectedMethod, gid=class java.lang.Long
方法: privateMethod, id=5, name=privateMethod, gid=class java.lang.Long
構造器: com.example.annotation.B, id=2, name=constructor, gid=class java.lang.Long
AnnotationProcessor 實現源碼生成、靜態檢查註解是 Java 元編程的基石。掌握其定義規範、生命週期控制與反射解析技巧,是理解主流框架原理、開發基礎設施組件的必備技能。