自定義注解是自己寫框架的必備技能副编,使用注解能極大地提升開發(fā)效率煮寡,因此自定義注解是一個高級開發(fā)者必備的技能。
要自定義注解趾诗,首先需要了解一個注解的構(gòu)成部分蜡感。
一個注解大致可以分為三個部分:注解體、元注解、注解屬性郑兴。
在在這三個主要組成部分中犀斋,注解體指定了注解的名字,而元注解則標(biāo)記了該注解的使用場景情连、留存時間等信息叽粹,而注解屬性則指明該注解擁有的屬性。
注解體
注解體是最簡單的一個組成部分蒙具,只需要像實例中一樣有樣學(xué)樣即可球榆。與接口的聲明唯一的不同是在 interface 關(guān)鍵字前多了一個 @ 符號。
//聲明了一個名為sweet的注解體
@Retention(RetentionPolicy.RUNTIME)
public @interface sweet{
}
元注解
元注解(meta-annotation)本身也是一個注解禁筏,用來標(biāo)記普通注解的存留時間持钉、使用場景、繼承屬性篱昔、文檔生成信息每强。
元注解是一個特殊的注解,它是 Java 源碼中就自帶的注解州刽。在Java 中只有四個元注解空执,它們分別是:@Target、@Retention穗椅、@Documented辨绊、@Inherited。
@Target注解
Target 注解限定了該注解的使用場景匹表。
它有下面這些取值:
- ElementType.ANNOTATION_TYPE 可以給一個注解進(jìn)行注解
- ElementType.CONSTRUCTOR 可以給構(gòu)造方法進(jìn)行注解
- ElementType.FIELD 可以給屬性進(jìn)行注解
- ElementType.LOCAL_VARIABLE 可以給局部變量進(jìn)行注解
- ElementType.METHOD 可以給方法進(jìn)行注解
- ElementType.PACKAGE 可以給一個包進(jìn)行注解
- ElementType.PARAMETER 可以給一個方法內(nèi)的參數(shù)進(jìn)行注解
- ElementType.TYPE 可以給一個類型進(jìn)行注解门坷,比如類、接口袍镀、枚舉
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface Autowired {
boolean required() default true;
}
在上面 Autowire的 注解中默蚌,其 Target 注解的值為 CONSTRUCTOR、METHOD苇羡、PARAMETER绸吸、FIELD、ANNOTATION_TYPE 這 5 個值设江。這表示 Autowired 注解只能在構(gòu)造方法锦茁、方法、方法形參绣硝、屬性蜻势、類型這 5 種場景下使用。
@Retention注解
Retention 注解用來標(biāo)記這個注解的留存時間鹉胖。
它其有四個可選值:
- RetentionPolicy.SOURCE握玛。注解只在源碼階段保留够傍,在編譯器進(jìn)行編譯時它將被丟棄忽視。
- RetentionPolicy.CLASS挠铲。注解只被保留到編譯進(jìn)行的時候冕屯,它并不會被加載到 JVM 中。
- RetentionPolicy.RUNTIME拂苹。注解可以保留到程序運行的時候安聘,它會被加載進(jìn)入到 JVM 中,所以在程序運行時可以獲取到它們瓢棒。
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
boolean required() default true;
}
在上面 Autowire的 注解中浴韭,其 Retention 注解的值為 RetentionPolicy.RUNTIME,說明該注解會保留到程序運行的時候脯宿。
@Documented
@ Documented 注解表示將注解信息寫入到 javadoc 文檔中念颈。
在默認(rèn)情況下,我們的注解信息是不會寫入到 Javadoc 文檔中的连霉。但如果該注解有 @Documented 標(biāo)識榴芳,那么該注解信息則會寫入到 javadoc 文檔中。
例如在下面這個例子中跺撼,我們聲明了一個 @Spicy 的注解窟感,沒有 @Documented 元注解。
public @interface Spicy {
String spicyLevel();
}
聲明一個 @Sweet 注解歉井,有 @Documented 元注解柿祈。
@Documented
public @interface Sweet {
String sweetLevel();
}
接下來寫一個 SweetDemo 類,類中的 sweetWithDoc 方法使用 @Sweet 注解哩至,spicyWithoutDoc 方法使用 @Spicy 注解谍夭。
public class SweetDemo {
public static void main(String arg[]) {
new SweetDemo().sweetWithDoc();
new SweetDemo().spicyWithoutDoc();
}
@Sweet (sweetLevel="Level.05")
public void sweetWithDoc() {
System.out.printf("sweet With Doc.");
}
@Spicy (spicyLevel="Level.04")
public void spicyWithoutDoc() {
System.out.printf("spicy Without Doc.");
}
}
最后我們使用 Javadoc 命令去生成對應(yīng)的 JavaDoc 文檔,打開文檔你會看到:sweetWithDoc方法上面有一個注解信息憨募,而 spicyWithoutDoc 方法上卻沒有注解信息。
這個就是 @Documented 這個元注解的作用袁辈。
@Inherited
@ Inherited注解標(biāo)識子類將繼承父類的注解屬性菜谣。
在下面的例子中,我們聲明了一個 Sweet 注解晚缩,接著在 Peach 類使用了 @Sweet 注解尾膊,但是并沒有在 RedPeach 類使用該注解。
//聲明一個Sweet注解荞彼,標(biāo)識甜味冈敛。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Sweet {}
//桃子有甜味
@Sweet
public class Peach {}
//紅色的水蜜桃
public class RedPeach extends Peach {}
雖然我們沒在 RedPeach 類上使用了 @Sweet 注解,但是我們在 Sweet 注解聲明中使用了 @Inherited 注解鸣皂,所以 RedPeach 繼承了 Peach 的 @Sweet 注解抓谴。
注解屬性
注解屬性類似于類方法的聲明暮蹂,注解屬性里有三部分信息,分別是:屬性名癌压、數(shù)據(jù)類型仰泻、默認(rèn)值。
在 @Autowired 注解中就聲明了一個名為 required 的 boolean 類型數(shù)據(jù)滩届,其默認(rèn)值是 true集侯。
public @interface Autowired {
boolean required() default true;
}
需要注意的是,注解中定義的屬性帜消,它的數(shù)據(jù)類型必須是 8 種基本數(shù)據(jù)類型(byte棠枉、short、int泡挺、long辈讶、float、double粘衬、boolean荞估、char)或者是類、接口稚新、注解及它們的數(shù)組勘伺。
總結(jié)
一個注解大致可以分為三個部分:注解體、元注解褂删、注解屬性飞醉。在這三個主要組成部分中:注解體指定了注解的名字、元注解則標(biāo)記了該注解的使用信息屯阀,注解屬性指明注解的屬性缅帘。
學(xué)習(xí)注解只要知道這三個部分就夠了,至于那些繁雜的屬性难衰,就用下面這張圖來解決吧钦无。用到的時候翻一翻,查一查盖袭,足矣失暂!
原文可見:注解的那些事兒(二)| 如何自定義注解