| 註解 | 目標 | 語義 | 編譯器行為 |
@Override | METHOD | 聲明覆寫父類/接口方法 | 若父類無此方法 → 編譯報錯,防止拼寫錯誤 |
@Deprecated | 所有 | 標記過時,不建議使用 | 使用處發出警告 |
@SuppressWarnings | 所有 | 抑制特定編譯警告 | value() 指定警告鍵 (unchecked, deprecation, rawtypes...) |
@Override 實戰防錯示例
public class Parent { public void foo() { System.out.println("Parent"); } }
public class Child extends Parent {
@Override
public void fob() { // 拼寫錯誤:應為 foo
System.out.println("Child");
}
}
// 編譯錯誤:Child.java:3: method does not override a method from its superclass
自定義註解:定義與使用
1. 定義註解類型
package com.example.anno;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) // 關鍵:運行時可反射獲取
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface MyTag {
String name() default "unknown";
int age() default 0;
String[] tags() default {}; // 數組屬性
}
2. 使用註解
@MyTag(name = "UserService", age = 1, tags = {"core", "biz"})
public class UserService {
@MyTag(name = "saveUser", age = 2)
public void save(User u) { /* ... */ }
}
3. 運行時反射解析
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class AnnotationParser {
public static void parse(Class> clazz) {
// 類級註解
if (clazz.isAnnotationPresent(MyTag.class)) {
MyTag tag = clazz.getAnnotation(MyTag.class);
System.out.printf("Class %s: name=%s, age=%d, tags=%s%n",
clazz.getSimpleName(), tag.name(), tag.age(), Arrays.toString(tag.tags()));
}
// 方法級註解
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(MyTag.class)) {
MyTag tag = m.getAnnotation(MyTag.class);
System.out.printf(" Method %s: name=%s, age=%d%n",
m.getName(), tag.name(), tag.age());
}
}
}
public static void main(String[] args) {
parse(UserService.class);
}
}
// 輸出:
// Class UserService: name=UserService, age=1, tags=[core, biz]
// Method save: name=saveUser, age=2
註解屬性類型限制
僅支援:基本類型、String、Class、enum、註解類型、以上類型的一維數組。不支援泛型、嵌套對象、集合。
進階應用模式
- 編譯期處理 (APT/Annotation Processor):實現
javax.annotation.processing.Processor,編譯階段掃描註解生成代碼/配置/資源 (如 Lombok、MapStruct、Dagger)。
- 運行時框架驅動:Spring
@Autowired/@Transactional、JPA @Entity/@Column、JAX-RS @Path/@GET,容器啟動掃描註解構建 Bean 定義/路由表/ORM 映射。
- 測試框架:JUnit
@Test/@BeforeEach、TestNG @DataProvider,運行器反射發現並執行。
- 代碼質量/文檔:SpotBugs
@SuppressFBWarnings、Swagger @ApiOperation、自定義 @Reviewed 追蹤代碼審查。
最佳實踐檢查清單
- [ ] 明確
@Retention(RUNTIME) 需求:僅文檔/編譯期用 CLASS,運行時反射必須 RUNTIME。
- [ ] 最小化
@Target 範圍:防止濫用於不相關元素。
- [ ] 提供合理
default 值:減少使用者樣板代碼。
- [ ] 屬性命名遵循 JavaBean 慣例:小寫駝峰,布爾型用
enabled() 而非 isEnabled()。
- [ ] 註解類型命名以
@Interface 結尾區分普通接口 (可選約定)。
- [ ] 文檔註解同步:
@Documented + 完整 Javadoc,IDE 懸停提示友好。
結語
JDK 5 註解機制將元數據從「文檔註釋」昇華為「可執行元數據」,奠定了現代 Java 框架 (Spring、Hibernate、JUnit、MyBatis…) 聲明式編程的基石。掌握標準註解防錯、自定義註解設計、反射解析與 APT 編譯期處理四大維度,是從 API 使用者進階為框架構建者的關鍵門檻。
- 上一篇文章: JDK 5 新特性實戰:ProcessBuilder 替代 Runtime.exec 執行外部進程
- 下一篇文章: J2SE 5.0 並發工具包深度解析:打造高效多執行緒應用
Copyright ©
程式碼之家 All Rights Reserved