程式碼中若使用了自訂標註,預設會將標註資訊儲存於.class檔案,可被編譯器或位元碼分析工具讀取,但執行時期無法讀取標註資訊。如果希望於執行時期讀取標註資訊,可以於自訂標註時使用java.lang.annotation.Retention
搭配java.lang.annotation.RetentionPolicy
列舉指定:
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, // 標註資訊留在原始碼(不會儲存至.class檔案)
CLASS, // 標註資訊會儲存至.class檔案,但執行時期無法讀取
RUNTIME //標註資訊會儲存至.class檔案,但執行時期可以讀取
}
RetentionPolicy
為SOURCE
的例子為@SuppressWarnings
,其作用僅在告知編譯器抑制警訊,所以不必將這個資訊儲存於.class檔案,@Override
也是,其作用僅在告知編譯器檢查是否真為重新定義方法。
RetentionPolicy
為RUNTIME
的時機,在於讓標註於執行時期提供應用程式資訊,可使用java.lang.reflect.AnnotatedElement
介面實作物件取得標註資訊,這個介面定義了幾個方法:
public Annotation getAnnotation(Class annotationType);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
public boolean isAnnotationPresent(Class annotationType);
Class
、Constructor
、Field
、Method
、Package
等類別,都實作了AnnotatedElement
介面,如果標註在定義時的RetentionPolicy
指定為RUNTIME
,就可以從Class
、Constructor
、Field
、Method
、Package
等類別的實例,取得設定的標註資訊。
舉個例子來說,假設你設計了以下的標註:
package cc.openhome;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Debug {
String name();
String value();
}
由於RetentionPolicy
為RUNTIME
,可以在執行時期讀取標註資訊,例如可將@Debug
用於程式中:
package cc.openhome;
public class Other {
@Debug(name = "caterpillar", value = "2011/10/10")
public void doOther() {
...略
}
}
以下的範例可用來讀取@Debug
設定的資訊,主要是透過Java的Reflection API:
package cc.openhome;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import static java.lang.System.out;
public class DebugTool {
public static void main(String[] args) throws NoSuchMethodException {
Class<Other> c = Other.class;
Method method = c.getMethod("doOther");
if(method.isAnnotationPresent(Debug.class)) {
out.println("已設定 @Debug 標註");
// 取得 @Debug 實例
Debug debug = method.getAnnotation(Debug.class);
out.printf("value: %s%n", debug.value());
out.printf("name : %s%n", debug.name());
} else {
out.println("沒有設定 @Debug 標註");
}
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations) {
out.println(annotation.annotationType().getName());
}
}
}
執行結果如下:
value: 2011/10/10
name : caterpillar
cc.openhome.Debug
一個使用標註的更實用範例,可以參考 使用小老鼠處理傾聽器。