ITEEDU

Java Gossip: 告知编译器如何处理 annotaion - Retention

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:

Debug.java
package onlyfun.caterpillar;
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用于程序中:

SomeObject.java
package onlyfun.caterpillar;
public class SomeObject {
	@Debug(
	value = "unit",
	name = "debug1"
	)
	public void doSomething() {?
		// ....
	}
}

可以设计一个工具程序来读取Annotation信息:

DebugTool.java
package onlyfun.caterpillar;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class DebugTool {
	public static void main(String[] args)
	throws NoSuchMethodException {
		Class 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
onlyfun.caterpillar.Debug