本文译自Java Annotations


Java Annotation Purposes

一般来说,Java Annotations有以下三种用途:

  • Compiler instructions
  • Build-time instructions
  • Runtime instructions

构建工具能够扫描Java代码中的annotations并基于这些annotations来生成源码或者文件。一般而言,编译后的Java代码中不会包含annotations,但是我们也可以定义运行时可见的annotations(这些annotations可以通过Java反射机制被访问到,并向我们的程序或者第三方API发出指令)。



创建我们自己的注解

每一个annotation都定义在其自己的.java文件中,就像定义类或者接口那样,如下

public @interface MyAnnotation {
	public String name();
	public String value();
	int age();
	String[] newNames();
}

注解中的element可以是primitive types,或者是数组,但是不能是复合类型。


如果注解有element,则在使用该注解时要指定每一个element的值,如

@MyAnnotation(name="NAME", value="VALUE",
		age=18, newNames={"1", "2", "3"})
public class Hello {
	public static void main(String[] args){	
		
	}	
}



当在定义注解时为某个element指定了默认值时,则使用该注解时可以不指定该element的值,如下

public @interface MyAnnotation {
	public String name() default "OK";
	public String value();
	int age();
	String[] newNames();
}
@MyAnnotation(value="VALUE", age=18, newNames={"1", "2", "3"})
public class Hello {
	public static void main(String[] args){	
		
	}	
}





@Retention

对于我们自定义的注解,可以通过@Retention注解来指定是否使其在运行时可见(通过反射),如下

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

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	public String name() default "OK";
	public String value();
	int age();
	String[] newNames();
}

其中,RetentionPolicy类包含了三种不同的值:

  • RetentionPolicy.RUNTIME : 指定本annotation在运行时可见
  • RetentionPolicy.CLASS : 指定本annotation将被存储在.class文件中,且在运行时不可见。如果没有指定任何retention策略,则RetentionPolicy.CLASS将是默认的策略
  • RetentionPolicy.SOURCE : 指定本annotation只存在于源代码中,在.class文件中不存在,且在运行时不可见。如果希望只让构建工具来利用这些annotation,可以使用该策略



@Target

使用@Target注解可以限制我们自定义的annotation只能修饰哪些Java元素,如下

import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Target({ElementType.METHOD})  // 限制本annotation只能用于Java中的方法
public @interface MyAnnotation {
	public String name() default "OK";
	public String value();
	int age();
	String[] newNames();
}

此外,ElementType类还有以下值:

  • ElementType.ANNOTATION_TYPE
  • ElementType.CONSTRUCTOR
  • ElementType.FIELD
  • ElementType.LOCAL_VARIABLE
  • ElementType.METHOD
  • ElementType.PACKAGE
  • ElementType.PARAMETER
  • ElementType.TYPE

其中,ElementType.TYPE可以应用于任何Java类型,包括class,interface, enum, 以及annotation。



@Inherited

如果一个annotation被@Inherited修饰,且类Base被该annotation修饰了,那么对于任何继承了类Base的子类(不妨称之为Derived类),类Derived也自动继承了该annotation。如下:

import java.lang.annotation.Inherited;

@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class A {
}
public class B extends A {

}






利用Java Reflection访问Annotations

访问Class Annotations

如果修饰某个类的annotations在定义是指定了@Retention(RetentionPolicy.RUNTIME)策略,那么可以在运行时访问该类中的annotations。

访问全部的annotations
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)	//注意,必须有本指令,否则在运行时本annotation是不可见的 
public @interface MyAnnotation {
	public String name();
	public String value();
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface AnotherAnnotation {
	public String anotherName();
	public String anotherValue();
}
import java.lang.annotation.Annotation;

@MyAnnotation(name="ccc", value="love")
@AnotherAnnotation(anotherName="xt", anotherValue="Real Love")
public class A {
	public static void main(String[] args) {
		Class aClass = A.class;
		Annotation[] annotations = aClass.getAnnotations();
		
		for (Annotation annotation : annotations) {
			if (annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation)annotation;
				System.out.println("name:" + myAnnotation.name());
				System.out.println("value:" + myAnnotation.value());
			} else if (annotation instanceof AnotherAnnotation) {
				AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
				System.out.println("another name: " + anotherAnnotation.anotherName());
				System.out.println("another value: " + anotherAnnotation.anotherValue());
			}			
		}
	}
}




访问某个指定的Annotation
import java.lang.annotation.Annotation;

@MyAnnotation(name="ccc", value="love")
@AnotherAnnotation(anotherName="xt", anotherValue="Real Love")
public class A {
	public static void main(String[] args) {
		Class aClass = A.class;
		Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
		if (annotation instanceof MyAnnotation) {
			MyAnnotation myAnnotation = (MyAnnotation)annotation;
			System.out.println("name:" + myAnnotation.name());
			System.out.println("name:" + myAnnotation.value());
		}
	}
}




访问Method Annotations

访问一个Method的全部Annotations
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class A {
	public static void main(String[] args) throws SecurityException, NoSuchMethodException {
		Class aClass = A.class;
		Method method = aClass.getMethod("func",null);
		
		Annotation[] annotations = method.getAnnotations();
		for (Annotation annotation : annotations) {
			if (annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation)annotation;
				System.out.println("name: " + myAnnotation.name());
				System.out.println("value: " + myAnnotation.value());
			} else if (annotation instanceof AnotherAnnotation) {
				AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
				System.out.println("name: " + anotherAnnotation.anotherName());
				System.out.println("value: " + anotherAnnotation.anotherValue());
			}			
		}
	}
	
	@MyAnnotation(name="000", value="111")
	@AnotherAnnotation(anotherName="aaa", anotherValue="bbb")
	public void func() {		
	}
}



访问一个Method的指定Annotation
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class A {
	public static void main(String[] args) throws SecurityException, NoSuchMethodException {
		Class aClass = A.class;
		Method method = aClass.getMethod("func", null);
		
		Annotation annotation = method.getAnnotation(AnotherAnnotation.class);
		if (annotation instanceof AnotherAnnotation) {
			AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
			System.out.println("name: " + anotherAnnotation.anotherName());
			System.out.println("value: " + anotherAnnotation.anotherValue());
		}			
	}
	
	@MyAnnotation(name="000", value="111")
	@AnotherAnnotation(anotherName="aaa", anotherValue="bbb")
	public void func() {		
	}
}



访问方法参数的annotations

MyAnnotation与AnotherAnnotation的定义如上所述,下面再增加一个OtherAnnotation

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

@Retention(RetentionPolicy.RUNTIME)
public @interface OtherAnnotation {
	public String otherName();
	public int otherValue();
}
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class A {
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Class aClass = A.class;
		Method method = aClass.getMethod("func", new Class[]{String.class, int.class});
		/* method.getParameterAnnotations()返回的是一个二维Annotation数组
		 * 第一个维度代表该method的一个参数,第二个维度代表该参数的annotations
		 * 所以该二维Annotation数组第一维度的数量 == 该method的参数数量 */		
		Annotation[][] annotationArray = method.getParameterAnnotations();		
		for (Annotation[] annotations : annotationArray) { 
			// 每一个annotations对象代表了一个参数的全部注解
			for (Annotation annotation : annotations) {
				if (annotation instanceof MyAnnotation) {
					MyAnnotation myAnnotation = (MyAnnotation)annotation;
					System.out.println("name: " + myAnnotation.name());
					System.out.println("value: " + myAnnotation.value());
				} else if (annotation instanceof AnotherAnnotation) {
					AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
					System.out.println("anotherName: " + anotherAnnotation.anotherName());
					System.out.println("anotherValue: " + anotherAnnotation.anotherValue());
				}  else if (annotation instanceof OtherAnnotation) {
					OtherAnnotation otherAnnotation = (OtherAnnotation)annotation;
					System.out.println("otherName: " + otherAnnotation.otherName());
					System.out.println("otherValue: " + otherAnnotation.otherValue());
				} 
			}
		}
	}
	
	public static void func(
		@MyAnnotation(name="ccc", value="love")	
		@AnotherAnnotation(anotherName="AAA", anotherValue="BBB") String str,	// 参数一
		@MyAnnotation(name="ccc", value="love") 
		@OtherAnnotation(otherName="XXX", otherValue=325) int n) 				// 参数二
	{

	}
	
}




访问field annotation
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class A {
	@MyAnnotation(name="m_x", value="xxx")
	@AnotherAnnotation(anotherName="m_y", anotherValue="yyy")
	@OtherAnnotation(otherName="m_z", otherValue=444)
	private String m_x;
	
	public static void main(String[] args) throws  NoSuchFieldException {
		Field field = A.class.getDeclaredField("m_x");
		Annotation[] annotations = field.getDeclaredAnnotations();
		
		for (Annotation annotation : annotations) {
			if (annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation)annotation;
				System.out.println("name: " + myAnnotation.name() + ", value: " + myAnnotation.value());
			} else if (annotation instanceof AnotherAnnotation) {
				AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
				System.out.println("anotherName: " + anotherAnnotation.anotherName() + ", anotherValue: " + anotherAnnotation.anotherValue());
			} else if (annotation instanceof OtherAnnotation) {
				OtherAnnotation otherAnnotation = (OtherAnnotation)annotation;
				System.out.println("otherName: " + otherAnnotation.otherName() + ", otherValue: " + otherAnnotation.otherValue());
			}
		}
	}	
}



还可以访问指定的annotation

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

public class A {
	@MyAnnotation(name="m_x", value="xxx")
	@AnotherAnnotation(anotherName="m_y", anotherValue="yyy")
	@OtherAnnotation(otherName="m_z", otherValue=444)
	private String m_x;
	
	public static void main(String[] args) throws  NoSuchFieldException {
		Field field = A.class.getDeclaredField("m_x");
		Annotation[] annotations = field.getDeclaredAnnotations();
		
		for (Annotation annotation : annotations) {
			if (annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation)annotation;
				System.out.println("name: " + myAnnotation.name() + ", value: " + myAnnotation.value());
			} else if (annotation instanceof AnotherAnnotation) {
				AnotherAnnotation anotherAnnotation = (AnotherAnnotation)annotation;
				System.out.println("anotherName: " + anotherAnnotation.anotherName() + ", anotherValue: " + anotherAnnotation.anotherValue());
			} else if (annotation instanceof OtherAnnotation) {
				OtherAnnotation otherAnnotation = (OtherAnnotation)annotation;
				System.out.println("otherName: " + otherAnnotation.otherName() + ", otherValue: " + otherAnnotation.otherValue());
			}
		}
	}	
}