執行時期捕鼠


java.lang.annotation.Retention可以在定義Annotation型態時,指示編 譯器如何對待自定義 Annotation,預設上編譯器會將Annotation資訊留在class檔案中,但不被虛擬機器讀取,而僅用於編譯器或工具程式運行時提供資訊。

在使用Retention型態時,需要提供java.lang.annotation.RetentionPolicy的列舉型態:
package java.lang.annotation;

public enum RetentionPolicy {
    SOURCE, // 編譯器處理完Annotation資訊後就沒事了
    CLASS, // 編譯器將Annotation儲存於class檔中,預設
    RUNTIME // 編譯器將Annotation儲存於class檔中,可由VM讀入
}

RetentionPolicy為SOURCE的例子是@SuppressWarnings,這個資訊的作用僅在告知編譯器抑制警訊,所以不必將這個資訊儲 存於class檔案。

RetentionPolicy為RUNTIME的時機,可像是您使用Java設計一個程式碼分析工具,您要VM讀出Annotation資訊,以在分析 程式中使用,搭配Reflection機制,就可以達到這個目的。

在J2SE 5.0中新增了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這個介面,所以您可以從這些類別的實例上,分別取得標示於其上的Annotation與其資訊,如果 RetentionPolicy為RUNTIME的話。

舉個例子來說,假設您設計了以下的Debug Annotation:
package cc.openhome;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Debug {
    String value();
    String name();
}

由於RetentionPolicy為RUNTIME,編譯器在處理Debug Annotation時,會將之編譯至class檔中,並可以VM讀出Annotation資訊,接著我們將Debug用於程式中:
package cc.openhome;
public class SomeObject {
    @Debug(
       value = "unit",
       name = "debug1"
    )
    public void doSomething() { 
        // ....     
    }
}


可以設計一個工具程式來讀取Annotation資訊:
package cc.openhome;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class DebugTool {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<SomeObject> c = SomeObject.class;

        Method method = c.getMethod("doSomething");
        if(method.isAnnotationPresent(Debug.class)) {
            System.out.println("@Debug is found.");

            Debug debug = method.getAnnotation(Debug.class);
            System.out.println("\tvalue = " + debug.value());
            System.out.println("\tname = " + debug.name());
        }
        else {
            System.out.println("@Debug is not found.");
        }

        Annotation[] annotations = method.getAnnotations();
        for(Annotation annotation : annotations) {
            System.out.println(
                    annotation.annotationType().getName());
        }
    }
}

程式的執行結果如下:
@Debug is found.
        value = unit
        name = debug1
cc.openhome.Debug