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