在某些狀況下,但願將相同的註解應用於聲明或類型用途。從Java SE 8發行版開始,重複註解使能夠執行此操做。html
例如,正在編寫代碼以使用計時器服務,該服務使可以在給定時間或某個計劃上運行方法,相似於UNIX cron服務。如今,要設置計時器以在該月的最後一天和每一個星期五晚上11:00 運行方法doPeriodicCleanup。要設置要運行的計時器,請建立一個@Schedule註解並將其應用於doPeriodicCleanup方法兩次。第一次使用指定月份的最後一天,第二次使用指定星期五晚上11點,以下面的代碼示例所示:java
@Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup() { ... }
前面的示例將註解應用於方法。能夠在使用標準註解的任何位置重複註解。例如,有一個用於處理未受權訪問異常的類。使用一個@Alert註解爲管理員註解併爲管理員添加另外一個註解:程序員
@Alert(role="Manager") @Alert(role="Administrator") public class UnauthorizedAccessException extends SecurityException { ... }
出於兼容性緣由,重複註解存儲在由Java編譯器自動生成的容器註解中。爲了使編譯器執行此操做,代碼中須要兩個聲明。正則表達式
第1步:聲明可重複的註解類型
註解類型必須使用@Repeatable元註解標記。如下示例定義自定義@Schedule可重複註解類型:數組
import java.lang.annotation.Repeatable; @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; }
@Repeatable括號 中的元註解的值是Java編譯器爲存儲重複註解而生成的容器註解的類型。在此示例中,包含註解類型是Schedules,所以重複@Schedule註解存儲在@Schedules註解中。oracle
將相同的註解應用於聲明而不首先聲明它是可重複的,這會致使編譯時錯誤。框架
第2步:聲明包含註解類型
包含註解類型必須具備value帶數組類型的元素。數組類型的組件類型必須是可重複的註解類型。Schedules包含註解類型的聲明以下:插件
public @interface Schedules { Schedule[] value(); }
Reflection API中有幾種可用於檢索註解的方法。返回單個註解的方法(例如 AnnotatedElement.getAnnotation(Class
設計註解類型時,必須考慮該類型註解的基數。如今可使用註解零次,一次,或者,若是註解的類型被標記爲@Repeatable屢次,則不止一次。還能夠經過使用@Target元註解來限制可使用註解類型的位置。例如,能夠建立只能在方法和字段上使用的可重複註解類型。仔細設計註解類型很是重要,以確保使用註解的程序員發現它儘量靈活和強大。設計
在Java SE 8發行版以前,註解只能應用於聲明。從Java SE 8發行版開始,註解也能夠應用於任何類型的使用。這意味着能夠在任何使用類型的地方使用註解。使用where類型的一些示例是類實例建立表達式(new),強制轉換,implements子句和throws子句。
new @Interned MyObject();
myString = (@NonNull String) str;
class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }
void monitorTemperature() throws @Critical TemperatureException { ... }
在元註解@Target中增長了做用類型:
/** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE
建立類型註解是爲了支持改進的Java程序分析,以確保更強的類型檢查。Java SE 8版本不提供類型檢查框架,但它容許編寫(或下載)類型檢查框架,該框架實現爲與Java編譯器結合使用的一個或多個可插入模塊。
例如,但願確保程序中的特定變量永遠不會分配給null; 你想避免觸發一個NullPointerException。能夠編寫自定義插件來檢查此問題。而後,將修改代碼以註解該特定變量,代表它從未分配給null。變量聲明可能以下所示:
@NonNull String str;
當編譯代碼(包括NonNull命令行中的模塊)時,編譯器會在檢測到潛在問題時輸出警告,容許修改代碼以免錯誤。在更正代碼以刪除全部警告後,程序運行時不會發生此特定錯誤。
可使用多個類型檢查模塊,其中每一個模塊檢查不一樣類型的錯誤。經過這種方式,能夠在Java類型系統的基礎上構建,在但願的時間和地點添加特定的檢查。
經過明智地使用類型註解和可插入類型檢查器的存在,能夠編寫更強大且更不容易出錯的代碼。
在許多狀況下,沒必要編寫本身的類型檢查模塊。有第三方爲你完成了這項工做。例如,可能但願利用華盛頓大學建立的Checker Framework。該框架包括一個NonNull模塊,一個正則表達式模塊和一個互斥鎖模塊。有關更多信息,請參閱 Checker Framework。
Repeating Annotations
Type Annotations and Pluggable Type Systems