注解(Annotation)是 Java 語(yǔ)言中一種特殊的元數(shù)據(jù)形式,它能在代碼中添加標(biāo)記信息,用于描述類、方法、變量等元素的特性(如權(quán)限、過期提示、校驗(yàn)規(guī)則等)。除了Java內(nèi)置的@Override、@Deprecated等注解,開發(fā)者還可以根據(jù)需求自定義注解,實(shí)現(xiàn)更靈活的元數(shù)據(jù)管理。了解自定義注解的方法及保留策略,是掌握注解應(yīng)用的核心。
一、Java 自定義注解的方法
自定義注解需使用@interface關(guān)鍵字,本質(zhì)上是一種特殊的接口,其定義需遵循特定語(yǔ)法,并可通過元注解(描述注解的注解)配置行為。
(一)基本語(yǔ)法與結(jié)構(gòu)
自定義注解的基本格式為:
// 元注解public @interface 注解名 { // 注解屬性(可選) 類型 屬性名() default 默認(rèn)值;}
元注解:用于修飾注解的注解,指定注解的保留策略、適用范圍等(詳見下文 “保留策略”)。
注解屬性:類似接口的方法聲明,需指定返回類型(基本類型、String、枚舉、注解或其數(shù)組),可通過default指定默認(rèn)值。
示例:定義一個(gè)用于標(biāo)記接口版本的注解Version
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;// 元注解:指定注解可用于類和接口@Target({ElementType.TYPE})// 元注解:指定保留策略為運(yùn)行時(shí)@Retention(RetentionPolicy.RUNTIME)public @interface Version { // 主版本號(hào),無(wú)默認(rèn)值(使用時(shí)必須指定) int major(); // 次版本號(hào),默認(rèn)值為0 int minor() default 0; // 版本描述,默認(rèn)值為"" String description() default "";}
(二)使用自定義注解
定義注解后,可在類、方法、變量等元素上使用,格式為@注解名(屬性名=值, ...),若屬性有默認(rèn)值可省略。
示例:使用Version注解標(biāo)記接口
// 使用注解,指定major,其他屬性用默認(rèn)值@Version(major = 1)public interface UserService { void getUser();}// 完整指定所有屬性@Version(major = 2, minor = 1, description = "支持分頁(yè)查詢")public interface OrderService { void getOrders(int pageNum, int pageSize);}
(三)解析自定義注解
注解本身僅為標(biāo)記,需通過反射機(jī)制解析才能發(fā)揮作用(如根據(jù)注解屬性執(zhí)行特定邏輯)。
示例:通過反射獲取類上的Version注解信息
import java.lang.reflect.AnnotatedElement;public class AnnotationParser { public static void parse(Class<?> clazz) { // 判斷類是否被Version注解標(biāo)記 if (clazz.isAnnotationPresent(Version.class)) { // 獲取注解實(shí)例 Version version = clazz.getAnnotation(Version.class); // 讀取注解屬性 System.out.println("類名:" + clazz.getSimpleName()); System.out.println("版本:" + version.major() + "." + version.minor()); System.out.println("描述:" + version.description()); } } public static void main(String[] args) { parse(UserService.class); // 解析UserService接口的注解 parse(OrderService.class); // 解析OrderService接口的注解 }}
解析結(jié)果會(huì)輸出兩個(gè)接口的版本信息,實(shí)現(xiàn)了通過注解傳遞元數(shù)據(jù)并動(dòng)態(tài)處理的功能。
二、注解的保留策略
注解的保留策略(Retention Policy)決定了注解在代碼生命周期(源碼、編譯期、運(yùn)行時(shí))的保留階段,通過元注解@Retention指定,有以下三種類型:
(一)SOURCE:僅保留在源碼中
注解僅在 Java 源文件中存在,編譯成字節(jié)碼(.class 文件)時(shí)被丟棄,不參與運(yùn)行時(shí)。
適用場(chǎng)景:用于編譯器檢查或代碼生成,如@Override(檢查方法重寫)、Lombok 的@Data(編譯時(shí)生成 getter/setter)。
示例:定義 SOURCE 級(jí)別的注解
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.SOURCE)public @interface Debug { String value() default "調(diào)試信息";}
該注解僅在源碼中可見,編譯后消失,無(wú)法通過反射獲取。
(二)CLASS:保留到字節(jié)碼中(默認(rèn)策略)
注解被編譯到字節(jié)碼中,但在 JVM 加載類時(shí)不被保留,運(yùn)行時(shí)無(wú)法通過反射訪問。
適用場(chǎng)景:用于字節(jié)碼增強(qiáng)工具(如 AspectJ)在編譯后、運(yùn)行前修改字節(jié)碼,實(shí)現(xiàn)特定功能(如日志切入)。
示例:定義 CLASS 級(jí)別的注解
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.CLASS)public @interface Log { String action();}
該注解存在于.class 文件中,但運(yùn)行時(shí)反射無(wú)法獲取,需通過字節(jié)碼工具處理。
(三)RUNTIME:保留到運(yùn)行時(shí)
注解被保留到 JVM 運(yùn)行階段,可通過反射機(jī)制動(dòng)態(tài)獲取注解信息,是最常用的保留策略。
適用場(chǎng)景:用于運(yùn)行時(shí)動(dòng)態(tài)邏輯處理,如 Spring 的@Controller(IOC 容器掃描)、JUnit 的@Test(測(cè)試方法識(shí)別)。
前面定義的Version注解即為 RUNTIME 級(jí)別,可在運(yùn)行時(shí)通過反射解析,實(shí)現(xiàn)靈活的業(yè)務(wù)邏輯。
三、自定義注解的常見應(yīng)用場(chǎng)景
代碼標(biāo)記與說明:如用@Deprecated標(biāo)記過時(shí)方法,自定義@Todo標(biāo)記待完成功能。
配置與參數(shù)校驗(yàn):如用@NotNull標(biāo)記必填參數(shù),通過解析注解實(shí)現(xiàn)參數(shù)合法性檢查。
框架與工具支持:如 Spring 通過@Autowired實(shí)現(xiàn)依賴注入,MyBatis 通過@Select映射 SQL 語(yǔ)句。
編譯期檢查:如自定義@NonEmpty注解,結(jié)合編譯器插件檢查集合是否為空。
四、自定義注解的注意事項(xiàng)
屬性類型限制:注解屬性的返回類型只能是基本類型、String、枚舉、注解或其數(shù)組,不能是普通類。
默認(rèn)值規(guī)則:若屬性無(wú)默認(rèn)值,使用注解時(shí)必須顯式指定值;數(shù)組類型的屬性賦值需用{}(如values = {1, 2})。
元注解配合:除@Retention外,常用元注解還有@Target(指定注解可修飾的元素類型,如類、方法)、@Inherited(允許子類繼承父類的注解)、@Documented(生成 API 文檔時(shí)包含注解)。
自定義注解是 Java 中實(shí)現(xiàn)元編程的重要手段,通過合理定義和解析注解,能顯著提升代碼的靈活性和可維護(hù)性。選擇合適的保留策略是關(guān)鍵:源碼級(jí)注解用于編譯檢查,字節(jié)碼級(jí)注解用于字節(jié)碼增強(qiáng),運(yùn)行時(shí)注解用于動(dòng)態(tài)邏輯處理。掌握自定義注解的方法,能幫助開發(fā)者更好地理解框架原理(如 Spring、MyBatis),并構(gòu)建更優(yōu)雅的代碼結(jié)構(gòu)。