一.重復注解
在某些情況下,希望將相同的注解應用於聲明或類型用途。從Java SE 8發行版開始,重復注解使可以執行此操作。
例如,正在編寫代碼以使用計時器服務,該服務使能夠在給定時間或某個計划上運行方法,類似於UNIX cron服務。現在,要設置計時器以在該月的最后一天和每個星期五晚上11:00 運行方法doPeriodicCleanup。要設置要運行的計時器,請創建一個@Schedule注解並將其應用於doPeriodicCleanup方法兩次。第一次使用指定月份的最后一天,第二次使用指定星期五晚上11點,如下面的代碼示例所示:
@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注解中。
將相同的注解應用於聲明而不首先聲明它是可重復的,這會導致編譯時錯誤。
第2步:聲明包含注解類型
包含注解類型必須具有value帶數組類型的元素。數組類型的組件類型必須是可重復的注解類型。Schedules包含注解類型的聲明如下:
public @interface Schedules {
Schedule[] value();
}
1.檢索注解
Reflection API中有幾種可用於檢索注解的方法。返回單個注解的方法(例如 AnnotatedElement.getAnnotation(Class
2.設計注意事項
設計注解類型時,必須考慮該類型注解的基數。現在可以使用注解零次,一次,或者,如果注解的類型被標記為@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