Java 使用反射處理註解

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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章