自定義註解
這是一篇前導文,爲後面打算寫的 Spring Boot 讀取不到啓動類中的自定義註解做鋪墊。
你既然都看到這篇文章了,想必比我都瞭解什麼是註解、註解能用來幹嘛。之前都對註解懷着“敬畏”的心態,覺得能自定義註解的人一定很厲害,確實的確如此,我見到過的那些人確實都非常厲害。不過話說回來了,註解也不是什麼牛鬼蛇神,它就是一個標籤,只不過是這個標籤保存在源代碼中,並且能被 annotation API 工具(我把它當做註解解析器)操作。如果只是定義一個註解,而不去寫它的解析器,那的確沒什麼卵用……
語法和規範
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Test {
int value() ;
int key() default 1;
}
上面就是最常見的註解的定義語法了,它用 @interface 關鍵字定義,註解中的屬性定義不太一樣,它用類似方法的形式,這些屬性要麼有默認值,要麼在使用註解時提供這些值,註解處理器其實就是利用反射來取到註解的屬性,然後再根據屬性值來具體做出相應處理。沒什麼,不要給自己設限。註解也會被編譯成 .class 文件
如果一個註解中沒有任何屬性,就被稱作標記註解(mark annotation)。
根據 Java Language Specification(JLS 9.6),註解的名字不能和類名或者接口名相同,原話如下:
It is a compile-time error if an annotation type has the same simple name as any of its enclosing classes or interfaces. 其實這也可以理解,畢竟都是以 .java 結尾嘛
所有的註解都直接繼承自 java.lang.annotation.Annotation(注意這貨是個接口),這也不難理解,Class 類中的 getAnnotations() 方法返回的都是 Annotation[] 類型的數組。
元註解
並不想去接受這些概念性質的東西,元註解是一種特殊的註解,它被設計用來解釋其他註解何時、何處起作用。說白了就是元註解專門負責新註解的創建,如上述你看到的 @Test 註解一樣。
Java 提供了四種元註解:
名稱 | 參數 |
---|---|
@Target | ElementType 類型的數組,指明註解能應用在何處,凡是你能想到的地方(類、方法聲明、參數、包甚至是局部變量)都能使用註解,具體在 ElementType 枚舉類中有定義 |
@Retention | 指明註解在什麼級別保存該註解,參數爲 RetentionPolicy 枚舉類,可選值有 SOURCE(被編譯器丟棄)、CLASS(在 class 文件中可用,會被 JVM 丟棄)、RUNTIME(JVM 運行時也保留該註解,可通過反射的方式讀取該註解的信息),一般情況下我們都是選擇 RUNTIMR,你可以留心一下 Lombok 大多是在 SOURCE 級別 |
@Documented | 此註解包含在 Javadoc 中 |
@Inheried | 允許子類繼承父類中的註解 |
我們定義自己的註解的時候,需要用這些元註解來指明這個註解可以被用到哪裏、在哪個級別起作用。
註解中若定義了名爲 value 的元素,並且在應用該註解的時候,此元素是唯一一個需要被賦值的元素,那麼此時無需使用 “名-值” 對的這種語法,只需在括號中給出 value 元素所需的值即可。——《Java 編程思想》
註解處理器
上面也說了,光有註解沒卵用,註解處理器纔會讓註解發揮出作用。
未完待續!
參考文章:
[1.] Java註解(三) 自定義註解與提取註解