Java 使用反射處理註解
自定義註解的格式:
[public|final] @interface 註解名
//@interface 表明:這是一個自定義註解
{
註解元素//註解元素 是無參數的方法
}
// 註解元素的格式:
數據類型 註解元素名() [default 默認值]
例子:
//自定義註解:
package test;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
//註解作用於類和方法的聲明上
@Retention(RetentionPolicy.RUNTIME)
//註解在運行時有效
public @interface UseAnno {
String value() default "user";
}
//使用自定義註解UseAnno
package test;
@UseAnno//在類上使用註解
public class AnnoC {
@UseAnno("註解作用在方法上")//在方法上使用註解
public void method() {
System.out.println("在方法上使用註解");
}
}
使用反射處理註解
利用反射可以在運行時動態獲取類的相關信息,如類的方法、屬性、構造方法。還可以創建對象、調用方法等。利用反射也可以獲取註解的相關信息。
反射是在運行時獲取相關信息的,要使用反射獲取註解的相關信息,這個註解必須是用@Retention(RetentionPolicy.RUNTIME)聲明的。
java.lang.reflect.AnnotatedElement接口定義了使用反射讀取註解信息的方法:
Annotation getAnnotation(Class annotationType)
//若存在該元素指定類型的註解,則返回這些註解,否則返回null。
Annotation[] getAnnotations()
//返回此元素上存在的所有註解。包括繼承的
Annotation[] getDeclaredAnnotations()
//返回該元素上存在的所有註解,不包括繼承的。
/*對於getAnnotations()和getDeclaredAnnotations():
如果沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。
該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。
*/
java.lang.Package.isAnnotationPresent:
public boolean isAnnotationPresent(類<? extends Annotation> annotationClass)
//若指定類型的註解存在於此元素上,則返回true,否則返回false
例:
aField.isAnnotationPresent(ApplianceMaker.class)
//意思是,判斷aField字段的註解是不是ApplianceMaker 類型
//自定義註解:
package test;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
//註解作用於類和方法的聲明上
@Retention(RetentionPolicy.RUNTIME)
//註解在運行時有效
public @interface UseAnno {
String value() default "user";
}
//使用自定義註解UseAnno
package test;
@UseAnno//在類上使用註解
public class AnnoC {
@UseAnno("註解作用在方法上")//在方法上使用註解
public void method() {
System.out.println("在方法上使用註解");
}
}
package test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
//利用反射獲取註解的值
public class ReflectAnno {
public static void main(String[] args) {
try {
Class c = Class.forName("test.AnnoC");
//獲取 使用註解的類 AnnoC 的Class對象c
Class cUse = Class.forName("test.UseAnno");
//獲取 註解類UseAnno 的Class對象cUser
Annotation anno = c.getAnnotation(cUse);
//獲取AnnoC類上使用的cUse註解 anno
if(anno != null) {
UseAnno a = (UseAnno) anno;
System.out.println("AnnoC類上的註解: " + a.value());
}
Method m = c.getDeclaredMethod("method");
Annotation an = m.getAnnotation(cUse);
//獲取method()方法上使用的cUse註解 an
if(an != null) {
UseAnno a = (UseAnno) an;
System.out.println("method()方法上的註釋: " + a.value());
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
/*輸出
AnnoC類上的註解: user
method()方法上的註釋: 註解作用在方法上
*/
//例子2
package test;
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME) // 元註解,運行時保留註解,必須有,否則註解值讀不出
@interface ApplianceMaker // 定義註解
{
// 定義註解元素,都有默認值
public String type() default "TV";
public String id() default "001";
public String maker() default "PandaTv";
public String address() default "BJ";
}
@Retention(RetentionPolicy.RUNTIME)
@interface ApplianceSaler // 定義註解
{
public String name() default "TM";
public String id() default "001";
public String address() default "HK";
}
@Retention(RetentionPolicy.RUNTIME)
@interface AppliancePrice // 定義註解
{
// 註解元素只有一個,名爲value
public int value() default 1200;
}
class Appliance {
// 爲域maker 加註解,給部分元素賦值,其餘用默認值
// 如果註解元素都用默認值,則直接寫@ApplianceMaker
@ApplianceMaker(type = "電腦", id = "201")
public String maker;
@ApplianceSaler(name = "JD", id = "222", address = "WH")
public String saler; // 域有註解
@AppliancePrice(999) // 也可以寫成"value=999",因爲只有一個,此處只寫出值即可
public int price; // 域有註解
public void setMaker(String m) {
maker = m;
}
public String getMaker() {
return maker;
}
public void setSaler(String saler) {
this.saler = saler;
}
public String getSaler() {
return saler;
}
public void setPrice(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
}
public class Test {
public static void main(String args[]) {
System.out.println(readAnnotation(Appliance.class));
}
// 讀註解信息
private static String readAnnotation(Class aClass) {
String maker = "製造商:";
String saler = "銷售商:";
String price = "價格:";
Field fields[] = aClass.getDeclaredFields(); // 獲取Appliance 類的所有字段
for (Field aField : fields) // 對每一個字段判斷其註解的類型
{
// 字段的註解是ApplianceMaker 類型
if (aField.isAnnotationPresent(ApplianceMaker.class)) {
ApplianceMaker aMaker; // 聲明一個註解變量
// 調用getAnnotation()方法獲得在aField 域上的註解“實例”
aMaker = (ApplianceMaker) aField.getAnnotation(ApplianceMaker.class);
maker += aMaker.type() + " "; // 獲取type 元素的值,其餘與此相同
maker += aMaker.id() + " ";
maker += aMaker.maker() + " ";
maker += aMaker.address() + "\n";
}
// 字段的註解是ApplianceSaler 類型
else if (aField.isAnnotationPresent(ApplianceSaler.class)) {
ApplianceSaler aSaler;
aSaler = (ApplianceSaler) aField.getAnnotation(ApplianceSaler.class);
saler += aSaler.name() + " ";
saler += aSaler.id() + " ";
saler += aSaler.address() + "\n";
}
// 字段的註解是AppliancePrice 類型
else if (aField.isAnnotationPresent(AppliancePrice.class)) {
AppliancePrice thePrice;
thePrice = (AppliancePrice) aField.getAnnotation(AppliancePrice.class);
price += thePrice.value();
}
}
return maker + saler + price;
}
}
/*輸出:
製造商:電腦 201 PandaTv BJ
銷售商:JD 222 WH
價格:999
*/