註解三要素
- 聲明:使用
@interface 定義註解類型
- 使用:在類/方法/欄位等標記註解
- 解析:透過反射 API 讀取註解資訊
元註解:配置註解行為
@Retention:生命週期
| 策略 | 說明 |
SOURCE | 僅原始碼保留,編譯器捨棄,.class 不含 |
CLASS(預設) | 編譯器記錄在 .class,但 VM 執行時不載入 |
RUNTIME | 編譯器記錄在 .class,VM 執行時保留,可反射讀取 |
@Target:適用位置
| ElementType | 適用目標 |
TYPE | 類、介面、枚舉、註解類型 |
FIELD | 欄位(含枚舉常數) |
METHOD | 方法 |
PARAMETER | 參數 |
CONSTRUCTOR | 建構子 |
LOCAL_VARIABLE | 區域變數 |
PACKAGE | 套件宣告 |
其他常用元註解
@Documented:納入 Javadoc
@Inherited:子類繼承父類註解(僅限 TYPE)
@Repeatable(Java 8+):允許同一位置重複標記
完整範例:自訂註解 MyAnnotation
1. 註解定義
package me.test;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
// 可定義屬性,如 String value() default "";
}
2. 使用註解
@MyAnnotation
class A { }
3. 反射解析
public class MyAnnotationTest {
public static void main(String[] args) {
// 判斷是否標記
if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
// 取得註解實例
MyAnnotation an = MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(an.toString()); // 輸出:@me.test.MyAnnotation()
}
}
}
進階反射 API
| 方法 | 回傳 | 說明 |
getAnnotation(Class<A>) | A | 取得指定類型註解(單一) |
getAnnotations() | Annotation[] | 取得所有註解(含繼承) |
getDeclaredAnnotations() | Annotation[] | 取得直接宣告的註解(不含繼承) |
isAnnotationPresent(Class) | boolean | 快速檢查是否存在 |
實戰應用場景
- 框架配置(Spring
@Autowired、@Transactional)
- 程式碼生成(Lombok
@Data、@Builder)
- 編譯期檢查(
@Override、@Deprecated、@SuppressWarnings)
- 測試框架(JUnit
@Test、@BeforeEach)
注意事項
- 註解屬性只能是基本型別、String、Class、枚舉、註解、或其陣列
- 屬性無法為 null,需提供
default 值
RUNTIME 保留會增加 .class 體積,按需選擇