1. 程式人生 > >程式語言中的各種反射

程式語言中的各種反射

        在最剛開始接觸設計模式的時候,那時候還是用的vb.net,對於反射只是懵懵懂懂,只知道把dll放到指定地方,就可以通過Assembly載入並獲取裡面的類。對於那個階段的反射,只是停留在了類的層次。

        後來,學習了JavaScript,這門指令碼語言,是弱型別、基於面向物件的(到現在依然還是懵懵懂懂)。這個裡面的反射,確切的說,JavaScript沒有完整的反射體系。但是在編碼中可以通過程式碼設計來完成類似反射的基本功能。還是比較簡單的吧。

        再後來,就是現在了,接觸了Java的反射。可以說真正接觸反射,就是從這裡開始的。

        說到底,反射到底是什麼?我們來看看百度百科怎麼說:程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言。Java不是動態語言,但Java有非常突出的動態相關機制,可以載入一個執行時才知名稱的class,獲悉其完整構造,並生成其物件實體、或對其fields設值、或喚起其methods。


        而對fields、methods的使用可以遍歷,可以通過字串進行指定,這也就使得不同類,可以呼叫相同的方法。例如:我現在有一個方法,接收一個Object型別的引數,我確定傳進來的Object都會有一個Id的屬性,我要獲取這個屬性,並對其進一步操作。

        現在該怎麼辦?在學了今天這篇博文後,你可以用commons-beanutils.jar包裡面的BeanUtils和PropertyUtils工具類。

        這個方法,只能獲取到指定類自身內部的屬性,對於父類裡面的屬性,是獲取不到的

public Object getFieldValue(Object object, String propertyName)  
		throws IllegalAccessException, NoSuchFieldException {
	//獲取Object的指定property
	Field field = object.getClass().getDeclaredField(propertyName);  
	//設定其可見性,若不設定,則無法獲取其值,如果獲取的屬性為public,則可以不加這句
	field.setAccessible(true);  

	return field.get(object);  
}  
        更多的時候,如果說傳入的Object都會有,那麼我們一般考慮將其抽象到父類裡,那麼上面的方法就不適合了。下面這個方法,可以獲取自身及父類裡面的所有屬性,思路其實很簡單,就是在當前類裡面獲取該欄位,如果沒有,就去其父類裡面獲取:
public Object getFieldValueInAllSuper(Object object, String propertyName)  
            throws IllegalAccessException, NoSuchFieldException {
	//獲取當前Object的class
	Class claszz=object.getClass();  
	Field field = null;  	  
	do{     
		try{  //從類裡面獲取指定屬性
			field = claszz.getDeclaredField(propertyName);  
		}  
		catch(NoSuchFieldException e){//如果沒有獲取到,則設定為null
			field=null;  
		}
		//設定當前class為父class
		claszz=claszz.getSuperclass();  
	} while(field==null&&claszz!=null); //當field為空且class不為空時,進行下次迴圈
	
	//如果field為空,說明沒有此欄位,返回空
	if(field==null) return null;  
	//如果不為空,設定可見性,然後返回
	field.setAccessible(true);  
	return field.get(object);  
}
        屬性反射完了,那麼現在來看一下方法應該怎樣動態呼叫呢?我只列一個不帶引數的方法呼叫,需要傳引數的同學自己研究一下~~
private String getId(Object o) throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException, NoSuchMethodException {
	//從當前類及父類中找
	return (String) o.getClass().getMethod("getId").invoke(o);
	//只查詢當前類
	return (String)o.getClass().getDeclaredMethod("getId").invoke(o);
}

        屬性、方法反射完了,那麼應該怎樣去動態的載入一個類呢?這裡就只提一下:用Class.forName()。其實我感覺這裡用的比較多的是傳入介面型別,然後獲取介面的class當作引數。

        最近這些日子,對於泛型、反射用的比以前多了很多,也體會到了它們的用處。最近的部落格,應該都會和這些有關,因為封裝,如果離了這兩個,真心感覺那將是惡夢~~