註解 是一種元資料格式,提供關於程式的資料,但不屬於程式碼本身,且不直接影響被註解代碼的運作。主要用途:
本教學涵蓋註解使用位置、應用方式、預定義註解類型、自訂註解、元註解、類型註解、可插拔型別系統與重複註解。
最簡形式:
@Entity
@ 標示後續為註解。帶元素的註解:
@Author(name = "Benjamin Franklin", date = "3/27/2003")
class MyClass { ... }
或單一元素可省略元素名:
@SuppressWarnings(value = "unchecked")
void myMethod() { ... }
無元素時括號可省略(如 @Override)。可在同一宣告套用多個註解:
@Author(name = "Jane Doe") @EBook
class MyClass { ... }
同類型重複註解自 Java SE 8 支援(詳見重複註解章節)。註解類型可為 JDK 內建(java.lang、java.lang.annotation)或自訂(如上例 @Author、@EBook)。
傳統上用於宣告:類別、欄位、方法等程式元素,慣例每行一個註解。Java SE 8 起擴展至型別使用場合:
new @Interned MyObject();myString = (@NonNull String) str;class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }void monitorTemperature() throws @Critical TemperatureException { ... }此類註解稱為類型註解,配合可插拔型別系統強化靜態檢查。
傳統以註解區塊記錄作者、版本等資訊:
public class Generation3List extends Generation2List {
// Author: John Doe
// Date: 3/17/2002
// ...
}
改用註解須先定義註解類型:
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
String[] reviewers();
}
@interface 關鍵字定義註解類型(本質為介面)。元素宣告類似方法,可指定預設值。使用時填寫值:
@ClassPreamble(
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List { ... }
java.lang 定義:@Deprecated、@Override、@SuppressWarnings、@SafeVarargs、@FunctionalInterface。
@deprecated 標籤說明替代方案(注意大小寫差異)。"deprecation"、"unchecked"),多重警告用陣列語法:@SuppressWarnings({"unchecked", "deprecation"})。定義於 java.lang.annotation:
SOURCE(原始碼層級,編譯器捨棄)、CLASS(類別檔保留,JVM 忽略,預設)、RUNTIME(JVM 保留,執行期可透過反射讀取)。ANNOTATION_TYPE、CONSTRUCTOR、FIELD、LOCAL_VARIABLE、METHOD、PACKAGE、PARAMETER、TYPE、TYPE_PARAMETER、TYPE_USE(後兩者 Java 8 新增)。Java 8 前註解僅限宣告,Java 8 擴展至任意型別使用場合(實例化、轉型、介面實作、拋出異常等)。此設計為改進 Java 強型別檢查鋪路:Java 8 未內建型別檢查框架,但允許編寫/下載可插拔模組整合編譯器。
範例:確保變數永不為 null,自訂 @NonNull 註解:
@NonNull String str;
編譯時掛載 NonNull 模組,編譯器偵測潛在空指標風險並警告。修正所有警告後,執行期該類錯誤不再發生。可疊加多檢查模組(正則、互斥鎖等),知名第三方框架如 Checker Framework(華盛頓大學)提供豐富模組。
Java 8 允許同一註解類型重複套用於同一宣告。範例:排程服務需在每月最後一天與每週五 23:00 執行:
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
或類別層級多角色通知:
@Alert(role="Manager")
@Alert(role="Administrator")
public class UnauthorizedAccessException extends SecurityException { ... }
@Repeatable 指定容器註解類型:import java.lang.annotation.Repeatable;
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
value,元件型別為可重複註解:public @interface Schedules {
Schedule[] value();
}
編譯器自動將重複註解封裝於容器註解中。未標註 @Repeatable 的註解重複使用會編譯錯誤。
反射 API 新增方法掃描容器註解一次回傳多個註解(如 AnnotatedElement.getAnnotations(Class)),舊方法 getAnnotationByType(Class) 僅回傳單一註解,相容既有程式碼。
設計註解類型時需考量基數(零次、一次、多次)、適用目標(@Target),確保 API 彈性與類型安全並重。