一、反射的理解
首先我們看看網友們對於反射的理解.
A: 正常情況是java虛擬機根據你的類的定義,創建出一個對象。反射則是相反的過程,可以根據一個對象的引用,解析它的定義信息(屬性,方法),進而可以操作它的屬性,調 用它的方法,當然也可以創建出新的對象。---來自qwqwqw408
B: 一句話來概括反射機制就是:動態地獲取類的一切信息,並利用這些信息做一些你想做的事情---來自justinavril
第一 反射可以操作某個類的私有變量和方法
第二 反射操作對象更加靈活 如 struts的form 只要有了form對象和 property名字就可以利用反射給property賦值和取值 對這類操作 一個方法就可以搞定。---來自<span style="color: rgb(102, 102, 102); font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 24px; background-color: rgb(245, 245, 245);"><strong>justinavril</strong></span>
C: 如果hibernate不用字段進行反射映射 那麼每個HQL的編譯和結果處理 將無法進行。
第三 反射方式調用方法 動態代理 擴展API 。sping ioc,aop也都是用的反射
第四 運行過程中對未知類進行初始化等
我都是用反射在竊取和擴展一些收費的無法反編譯的API---來自a276202460
沒有錯,他們說的都對就是對類的動態加載,你可以通過反射來操縱類中的一切,無論這個類中的變量和方法是不是private,我們都可以應用。
二、反射機制中需要使用到的類
我把需要使用的類列在下表中,其中對我們特別有用的類,通過着重標記顯示出來,並將在後面的使用中逐步解釋:
三、Class類
首先向大家說明一點,Class本身就是一個類,Class是該類的名稱。看以下下面這個類的定義:
public class MyButton extends Button {...}
注意到上面的class的首字母是小寫,它表示的是一種類類型,但是我們的Class是一個類,相當於上面定義的MyButton類。所以,千萬不要把這裏的Class做爲一個類類型來理解。明白這一點,我們繼續。
Class類是整個Java反射機制的源頭,Class類本身表示Java對象的類型,我們可通過一個Object對象的getClass()方法取得一個對象的類型,此函數返回的就是一個Class類。獲取Class對象的方法有很多種:
boolean.class byte.class int.class long.class float.class double.class
在平時的使用,要注意對這幾種方法的靈活運用,尤其是對Class.forName()方法的使用。因爲在很多開發中,會直接通過類的名稱取得Class類的對象。
四、獲取類的相關信息
1、獲取構造方法
Class類提供了四個public方法,用於獲取某個類的構造方法。
Constructor getConstructor(Class[] params) 根據構造函數的參數,返回一個具體的具有public屬性的構造函數
Constructor getConstructors() 返回所有具有public屬性的構造函數數組
Constructor getDeclaredConstructor(Class[] params) 根據構造函數的參數,返回一個具體的構造函數(不分public和非public屬性)
Constructor getDeclaredConstructors() 返回該類中所有的構造函數數組(不分public和非public屬性)
由於Java語言是一種面向對象的語言,具有多態的性質,那麼我們可以通過構造方法的參數列表的不同,來調用不同的構造方法去創建類的實例。同樣,獲取不同的構造方法的信息,也需要提供與之對應的參數類型信息;因此,就產生了以上四種不同的獲取構造方法的方式。
2、獲取類的成員方法
與獲取構造方法的方式相同,存在四種獲取成員方法的方式。
Method getMethod(String name, Class[] params) 根據方法名和參數,返回一個具體的具有public屬性的方法
Method[] getMethods() 返回所有具有public屬性的方法數組
Method getDeclaredMethod(String name, Class[] params) 根據方法名和參數,返回一個具體的方法(不分public和非public屬性)
Method[] getDeclaredMethods() 返回該類中的所有的方法數組(不分public和非public屬性)
在獲取類的成員方法時,有一個地方值得大家注意,就是getMethods()方法和getDeclaredMethods()方法。
getMethods():用於獲取類的所有的public修飾域的成員方法,包括從父類繼承的public方法和實現接口的public方法;
getDeclaredMethods():用於獲取在當前類中定義的所有的成員方法和實現的接口方法,不包括從父類繼承的方法。
3、獲取類的成員變量(成員屬性)
存在四種獲取成員屬性的方法
Field getField(String name) 根據變量名,返回一個具體的具有public屬性的成員變量
Field[] getFields() 返回具有public屬性的成員變量的數組
Field getDeclaredField(String name) 根據變量名,返回一個成員變量(不分public和非public屬性)
Field[] getDelcaredField() 返回所有成員變量組成的數組(不分public和非public屬性)
4、獲取類、屬性、方法的修飾域
類Class、Method、Constructor、Field都有一個public方法int getModifiers()。該方法返回一個int類型的數,表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。
在開發文檔中,可以查閱到,Modifier類中定義了若干特定的修飾域,每個修飾域都是一個固定的int數值,列表如下:
五、如何調用類中的private方法
1、創建一個類的實例
在得到一個類的Class對象之後,我們可以利用類Constructor去實例化該對象。Constructor支持泛型,也就是它本身應該是Constructor<T>。
//獲得無參數的構造函數
Constructor constructor = animalClass03.getConstructor(null);
//通過獲得的無參數構造器可以 通過newInstance來實現一個對象;
Object monkey01 = constructor.newInstance();
2、行爲
Method類中包含着類的成員方法的信息。在Method類中有一個public成員函數:Object invoke(Object receiver, Object... args),參數receiver指明瞭調用對象,參數args指明瞭該方法所需要接收的參數。由於我們是在運行時動態的調用類的方法,無法提前知道該類的參數類型和返回值類型,所以傳入的參數的類型是Object,返回的類型也是Object。(因爲Object類是所有其他類的父類)
/**獲得類的方法並調用方法**///其實和變量沒有太大的區別,區別是增加了參數而已
Method[] methods = animalClass03.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
if(methods[i].getName().equals("yaoWeiba")){
methods[i].setAccessible(true);
Object[] parameters = new Object[]{
new String("小強"),true,3
};
methods[i].invoke(monkey03, parameters);
}
}
3、屬性
對類的成員變量進行讀寫,在Field類中有兩個public方法:
Object get(Object object),該方法可用於獲取某成員變量的值
Void set(Object object, Object value),該方法設置某成員變量的值
其中,Object參數是需要傳入的對象;如果成員變量是靜態屬性,在object可傳入null。
//獲得類中所有的變量,但是隻有自己類中的變量,沒有父類繼承過來的變量
Field[] fieldsAll = animalClass03.getDeclaredFields();
for(int i=0;i<fieldsAll.length;i++){
System.out.println(fieldsAll[i].getName());
fieldsAll[i].setAccessible(true);//private 的變量通過這個設置後,我們也可以爲其賦值了,不然不能訪問
//如果變量時String類型的,那麼我們就爲這個變量賦值,爲monkey03這個對象中的tile賦值
if(fieldsAll[0].getType()==String.class){
fieldsAll[0].set(monkey03, "長尾巴");
}
}