首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 註解 (Annotation) 進階:自訂註解類型、成員預設值與元註解完整指南

     編輯:Java 相關知識

承接第一部分 (內建註解 @Override、@Deprecated、@SuppressWarnings),本文深入自訂註解類型定義、成員設計、預設值、以及元註解 (註解的註解) 完整機制。

一、定義自訂註解類型

@interface 宣告

語法類似介面,但 interface 前加 @。最簡單範例:


package com.oreilly.tiger.ch06;
/** 標記註解:指示方法/類別仍在處理中 */
public @interface InProgress { }

使用方式與內建註解相同:


@com.oreilly.tiger.ch06.InProgress
public void calculateInterest(float amount, float rate) { /* ... */ }

可 import 後直接用 @InProgress。

新增成員 (資料欄位)

成員以無參方法形式宣告,方法名 = 成員名,回傳型別 = 成員型別。無需 getter/setter。


public @interface TODO {
    String value();  // 單一成員慣命名為 value
}

使用:


@TODO("Figure out the amount of interest per month")
public void calculateInterest(float amount, float rate) { /* ... */ }

簡寫規則:僅當註解類型只有單一成員且名為 value 時,可省略成員名直接給值。否則需完整寫法:


@TODO(value = "Figure out the amount of interest per month")

設定預設值

在成員宣告後加 default 關鍵字:


public @interface GroupTODO {
    public enum Severity { CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION }
    Severity severity() default Severity.IMPORTANT;
    String item();
    String assignedTo();
    String dateAssigned();
}

使用時可省略預設值成員:


@GroupTODO(
    item = "Figure out the amount of interest per month",
    assignedTo = "Brett McLaughlin",
    dateAssigned = "08/04/2004"
    // severity 將自動套用 IMPORTANT
)

也可顯式覆寫:


@GroupTODO(
    severity = GroupTODO.Severity.DOCUMENTATION,
    item = "Need to explain how this rather unusual method works",
    assignedTo = "Jon Stevens",
    dateAssigned = "07/30/2004"
)

二、元註解:對註解的註解

四種預定義元註解,賦予自訂註解語義約束與行為控制。

1. @Target — 限定適用程式元素

參數為 ElementType 列舉陣列:


public enum ElementType {
    TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
    LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE
}

範例:限定 @TODO 僅能用於類型、方法、建構子、其他註解類型:


@Target({ElementType.TYPE, ElementType.METHOD,
         ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
public @interface TODO { String value(); }

編譯器將阻止錯誤使用位置 (如套用在欄位上)。

2. @Retention — 設定保留策略

參數為 RetentionPolicy 列舉:


public enum RetentionPolicy {
    SOURCE,  // 編譯器捨棄,不進 class 檔
    CLASS,   // 存入 class 檔,但 VM 忽略 (預設)
    RUNTIME  // 存入 class 檔,VM 載入可透過反射讀取
}

範例:@SuppressWarnings 僅需原始碼階段生效:


@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings { /* ... */ }

CLASS 為預設,無需顯式聲明。

3. @Documented — 納入 Javadoc

標記註解 (無成員)。預設註解**不出現在 Javadoc** 中。加上此元註解可將註解資訊輸出至類別 HTML 文件。


@Documented
@Retention(RetentionPolicy.RUNTIME)  // 必須為 RUNTIME
public @interface InProgress { }

關鍵:Javadoc 從 class 檔透過 VM 讀取資訊,**必須設定 RUNTIME 保留策略**,否則 Javadoc 讀不到。

4. @Inherited — 繼承傳遞

預設註解**不會**被子類別繼承。加上此元註解後,父類別的註解會出現在子類別中 (透過反射可見)。


@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }

適用場景:標記類別狀態 (如「開發中」) 需傳遞給子類。不適用:@TODO 等任務型註解不應傳遞。

三、完整範例:綜合應用


package com.oreilly.tiger.ch06;

import java.lang.annotation.*;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Feature {
    String id();
    String description() default "";
    Status status() default Status.PLANNED;

    public enum Status { PLANNED, IN_PROGRESS, COMPLETED, DEPRECATED }
}

使用:


@Feature(id = "AUTH-001", description = "OAuth2 整合", status = Feature.Status.IN_PROGRESS)
public class AuthService { /* ... */ }

四、最佳實踐與避坑指南

  1. 克制使用:如同 Javadoc 早期濫用,註解亦易過度。僅在「編譯器檢查」、「工具處理」、「框架整合」三大剛需場景使用
  2. 標準註解優先:@Override、@Deprecated、@SuppressWarnings、@FunctionalInterface、@SafeVarargs 等標準註解已涵蓋大多數需求
  3. 元註解完整聲明:自訂註解**必須**明確指定 @Target、@Retention,避免預設行為導致誤用
  4. 保留策略最小化:能用 SOURCE 不用 CLASS,能用 CLASS 不用 RUNTIME (除非需反射讀取或 Javadoc)
  5. 成員型別限制:註解成員型別僅限基本型別、String、Class、enum、註解類型、及上述類型的一維陣列
  6. 命名規範:單一成員命名 value 享受簡寫語法;多成員採描述性名稱

總結

自訂註解 = @interface + 成員方法 + 元註解約束。@Target 限位置、@Retention 控生命週期、@Documented 進文件、@Inherited 傳子類。善用註解可構建強大的編譯期檢查、程式碼分析與框架整合能力,但**切勿濫用** — 最好的註解是「不寫也能懂」的程式碼本身。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved