JAVA基礎——java動態性之反射

一、簡介:

    java不算是動態語言,但是卻含有一些動態性機制功能。體現java動態性的有:反射機制、動態編譯、動態執行javascript代碼和動態字節碼操作等。在這裏介紹一下java動態性中的反射機制。反射機制是在java程序運行狀態中,可以動態的記載類,對於已經加載的類,可以知道這個類的所有屬性和方法,也可以操作其對象的相關屬性和方法。加載類之後會在堆內存中生成該類的一個Class類型的對象,該對象中包含該類的結構信息,結構信息和類的相關信息形成一種映射關係,這就體現了類本身和Class對象的反射關係。

二、操作:

    1、Class類型對象的獲取:

    獲取Class類型對象有三種方法,如下語句:

<pre class="java" name="code">	Class clazz = Class.forName(path);
	Class strClazz = String.class;
	Class strClazz2 = path.getClass(); 

    其中常用的還是Class.forName(對象名)這個方法。

    2、利用反射API獲取和操作類的相關信息。

    其核心代碼如下:

	Class<User> clazz = (Class<User>) Class.forName(path);

	//通過反射API調用構造方法,構造對象
	//1、調用User無參構造方法生成新對象
	User u = clazz.newInstance();
	//2、調用User指定參數的構造方法生成新對象。
	Constructor<User> c = 
		clazz.getDeclaredConstructor(int.class,int.class,String.class);
	User u2 = c.newInstance(1001,18,"高淇二");

	//通過反射API調用普通方法
	User u3 = clazz.newInstance();
	Method method = clazz.getDeclaredMethod("setUname", String.class);
	method.invoke(u3, "高淇三");   //相當於u3.setUname("高淇三");

	//通過反射API操作屬性
	User u4 = clazz.newInstance();
	Field f = clazz.getDeclaredField("uname");
	f.setAccessible(true); //指定屬性不需要做安全檢查了,可以直接訪問
	f.set(u4, "高淇四");		//通過反射直接寫屬性

    下邊說明有關setAccessible方法,一般情況下反射只可以訪問類中的非靜態成員,如果要訪問類中的靜態成員,需要通過setAccessible方法設置該屬性可以直接訪問不需要做安全檢查;反射的一大缺點就是需要速度慢,主要就是在於每次訪問都需要做安全檢查,因此如果需要避免反射速度慢的缺點,必要時候也會犧牲安全因素,提高運行速度,這時就需要通過setAccessible方法進行設置。

    3、通過反射獲取泛型:

    核心代碼如下:

	//獲得指定方法參數泛型信息
	Method m = Demo04.class.getMethod("test01", Map.class,List.class);
	Type[] t = m.getGenericParameterTypes();
	for (Type paramType : t) {
		System.out.println("#"+paramType);
		if(paramType instanceof ParameterizedType){
			Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
			for (Type genericType : genericTypes) {
				System.out.println("泛型類型:"+genericType);
			}
		}
	}

	//獲得指定方法返回值泛型信息
	Method m2 = Demo04.class.getMethod("test02", null);
	Type returnType = m2.getGenericReturnType();
	if(returnType instanceof ParameterizedType){
		Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
		for (Type genericType : genericTypes) {
			System.out.println("返回值,泛型類型:"+genericType);
		}	
	}

    4、反射操作註解:

    有關操作註解:這裏定義了兩個自定義的註解和一個操作類,SxtTable、SxtField以及Demo類,用於模擬代碼信息生成數據庫對應表信息的過程,其相關代碼如下:

    自定義註解SxtTable:

@Target(value={ElementType.TYPE}) //修飾範圍爲類或接口等。
@Retention(RetentionPolicy.RUNTIME) //定義註解的生命週期。
public @interface SxtTable {
	String value();
}

    自定義註解SxtField:

@Target(value={ElementType.FIELD}) //修飾範圍爲類型成員。
@Retention(RetentionPolicy.RUNTIME) //定義註解的生命週期。
public @interface SxtField {
	String columnName();
	String type();
	int length();
}

    操作類:

@SxtTable("tb_student")
public class SxtStudent {

	@SxtField(columnName="id",type="int",length=10)
	private int id;
	@SxtField(columnName="sname",type="varchar",length=10)
	private String studentName;
	@SxtField(columnName="age",type="int",length=3)
	private int age;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getStudentName() {
		return studentName;
	}
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}


三、總結:

    通過反射初步認識了有關java動態性的一些操作,但是有關反射的運用遠遠不止這些,反射是java中非常有力的一個功能,當然反射也有自己的一些缺陷,在運用中需要權衡好其利弊,儘量做到將其利益最大化。


發佈了90 篇原創文章 · 獲贊 57 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章