本文译自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());
}
}
}
}