標籤:
1. 概念
反射就是將java類中的各種成分映射成相應的java類。之前我們已經講過了Class類,也明白了一個java類中用一個Class類的對象來表示,一個類中的組成部分有:成員變數,方法,構造方法,包等等資訊也用一個個的java類來表示。
舉個生活中的例子,生活中我們經常見到汽車,如果說汽車是一個類的話,那麼汽車中的發動機、變速箱等等也是一個個的類。表示java類的Class類顯然要提供一系列的方法,來獲得其中的變數,方法,構造方法,修飾符,包等資訊,這些資訊就是用相應類的執行個體對象來表示的,就是Field,Method,Contructor以及Package等等。
2. 機制及應用場合
在運行狀態中,對於任何一個類,都能夠知道這個類的所以的屬性和方法;對於任何一個對象,都能夠調用它的任意一個方法和屬性;這種動態擷取資訊以及動態調用對象的方法就是反射,java反射的動態機制是Reflection,指的就是可以用於運行期間的載入和探知,使用編譯期間完全未知的classes。換言之,java程式課可以載入一個運行時才知道的class,獲悉其完整構造(不包含method定義)。
在編譯時間根本無法知道該對象或者類可能屬於哪些類,程式只是依靠運行時的資訊來發現該對象和類的真實的資訊。
3. 作用
通過反射我們可以使程式碼訪問裝載到JVM中的類的內部資訊,擷取已裝載類的屬性資訊、方法、構造方法的資訊。
我們前面的介紹到了Class類是java反射機制的起源和入口,使用者擷取與類相關的各種資訊,提供了擷取類資訊的相關的方法,Class類繼承自Object類,Class類是所有類的共同的圖紙。
Class類的一些方法如所示:
4. 各種反射的應用 ? 構造方法 Constructor類
一個類有多個構造方法,根據參數的個數和類型不用來區別,java中的構造方法是沒有順序的;利用構造方法類型的方法可以反射得到相應的類;由構造方法可以得到相應的執行個體對象,根據方法的反射得到這個構造方法到底是哪個類的構造方法,如下面所示:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>Constructor constructor1 = String.class.getConstructor(StringBuffer.class);String str2 = (String) constructor1.newInstance(new StringBuffer("abc"));</strong></span>
只是知道是個構造方法,但是不知道是哪個構造方法,只有在啟動並執行時候才能知道
上例中我們看到存在兩個StringBuffer,
第一個表示用的是String眾多中哪個構造方法,由上例可知,用的是參數為StringBuffer的構造方法。表示的是獲得方法時要用到類型。
第二個表示是用的時候必須傳入一個stringbuffer的對象;利用構造方法的newInstance反射可以得到這個類的執行個體對象,建立這個類型執行個體對象,從而將構造方法的相同的型別參數進行傳入表示調用了某個方法。調用擷取的方法時要用到上面相同類型的執行個體對象。
值得注意的是:參數必須是匹配的,如果不匹配,則會報錯。編譯的時候只是執行語法檢查,並不執行等號右邊的代碼,只是在啟動並執行時候才能知道其是一個String,故而下面的要加上(String)。
Ps:除了構造方法具有newInstance()方法外,Class同樣具有,也就是Class.newInstance(),比如:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>Stringobj=(String)Class.forName(“java.lang.String”).newInstance();</strong></span>
該方法內部先得到預設的構造方法,然後用該構造方法建立執行個體對象。
? 成員變數 Filed類
定義一個ReflectPoint類,然後在一個類中進行調用。
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>ReflectPoint pt1 = new ReflectPoint(3, 5);Field fieldY = pt1.getClass().getField("y");System.out.println(fieldY.get(pt1));System.out.println(fieldY);</strong></span>
Field fieldY = pt1.getClass().getField("y");如果你認為這個運算式得到的值是5,那就錯了,fieldY不是對象身上的變數,而是類上的,要用它去取某個對象上對應的值。
fieldY.get(pt1),上面我們知道fieldY是某個類上的變數,傳回型別是個類型,也可以說是一個類,利用它的get方法可以反射得到相應的執行個體對象並且擷取執行個體對象上對應的值。
? 成員方法的反射
就是一個類中定義的方法,Method類代表某個類中的一個成員方法,將一個類中各個成分反射成其對應的java類就是反射。
得到類中的一個方法,利用getMethod得到的是一個Method類型的類,並且可以在括弧中匹配相應的參數類型與類名。反射方式得到位元組碼中的方法,再拿出這個方法去作用於某個對象。
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>Method methodCharAt = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt.invoke(str1, 1));</strong></span> 方法的調用肯定是基於某個對象的:
1.也就是在對象str1身上調用了定義charAt方法(methodCharAt)方法,後面的1是方法的參數
2.利用反射的方式得到位元組碼中的方法,再拿出這個方法作用於某個對象。Invoke表示的是調用。
3.也就是方法執行了調用的動作,invoke是這個方法對象身上的方法。
故而invoke中第一個即為相應的執行個體對象,第二個為參數,不管參數有無,均稱之為參數。
舉個簡單的例子:
畫圓或者火車停車只是人發訊號,操作由其本身來執行。方法是對象本身在調用,而人只是發了個通知或者訊號,執行的動作只是自己的動作。人的作用就是發訊號和通知而已,也就是說誰擁有資料誰就是專家,也就是對象本身。
什麼方法調用時是不需要對象?答案是靜態方法。靜態方法調用的時候不需要對象,所以不需要對象的肯定是靜態方法。運用方法的方法反射得到某個執行個體對象。
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>Method methodCharAt = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt.invoke(null, 1));</strong></span> 5. 小結
反射就是將java類中的各個成分反射成相應的類,熟悉以及掌握反射將會協助我們更好地開發程式。學習研究仍在繼續。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Java之旅(2)—反射