您好,登錄后才能下訂單哦!
關(guān)于Java反射,我們需要弄懂以下幾個問題:
反射是什么?反射有什么用?怎么用反射?
下面我們來一一進(jìn)行講解:
一、反射是什么?
Reflection的意思是“反射、映象、倒影”,用在Java身上指的是我們可以于運(yùn)行時加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個運(yùn)行時才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods。
Java反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性及方法;對于任何一個對象,都能夠調(diào)用它的任意一個方法;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象的方法的功能稱為Java的反射機(jī)制。
1.自省(Introspection)vs.反射(Reflection)
反射經(jīng)常和自省弄混,為了區(qū)別,我們先看看兩者的詳細(xì)定義:
自省(Introspection):
Introspectionistheabilityofaprogramtoexaminethetypeorpropertiesof
anobjectatruntime.
反射(Reflection):
Reflectionistheabilityofaprogramtoexamineandmodifythestructure
andbehaviorofanobjectatruntime.
從上述定義,我們可以看出,自省是反射的子集。部分語言支持自省,但是不支持反射,比如C++。
2.自省示例vs.反射示例
自省示例:instanceof操作符用于判斷一個對象是否屬于一個特定的類。
if(obj instanceof Dog) { Dog d = (Dog)obj; d.bark(); }
反射實(shí)例: Class.forName()方法返回了一個具體類/接口的對象,當(dāng)然參數(shù)需要指定為特定的類名。
// with reflection Class <!--?--> c = Class.forName("classpath.and.classname"); Object dog = c.newInstance(); Method m = c.getDeclaredMethod("bark", new Class<!--?-->[0]); m.invoke(dog);
二、 為什么需要反射?
Java反射在框架開發(fā)中尤為重要。有些情況下,我們要使用的類在運(yùn)行時才會確定,這個時候我們不能在編譯期就使用它,因此只能通過反射的形式來使用在運(yùn)行時才存在的類(該類符合某種特定的規(guī)范,例如JDBC),這是反射用得比較多的場景。
編譯時我們對于類的內(nèi)部信息不可知,必須得到運(yùn)行時才能獲取類的具體信息。比如ORM框架,在運(yùn)行時才能夠獲取類中的各個屬性,然后通過反射的形式獲取其屬性名和值,存入數(shù)據(jù)庫。
反射機(jī)制提供的功能:
在運(yùn)行時判斷任意一個對象所屬的類; 在運(yùn)行時構(gòu)造任意一個類的對象; 在運(yùn)行時判斷任意一個類所具有的成員變量和方法; 在運(yùn)行時調(diào)用任意一個對象的方法。通過反射甚至可以調(diào)用到private的方法; 在運(yùn)行時修改構(gòu)造函數(shù),變量和方法的訪問權(quán)限。
解耦
假如我們有兩個程序員,一個程序員在寫程序的時候,需要使用第二個程序員所寫的類,但第二個程序員并沒完成他所寫的類。那么第一個程序員的代碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機(jī)制,就可以讓第一個程序員在沒有得到第二個程序員所寫的類的時候,來完成自身代碼的編譯
在對類的調(diào)用和實(shí)例化的時候,通過在配置文件中配置相應(yīng)的類名,在程序中讀取類名,然后通過反射技術(shù)在程序中加載和實(shí)例化,如常見的數(shù)據(jù)庫驅(qū)動程序類,為了達(dá)到不依賴特定數(shù)據(jù)庫驅(qū)動類,將用到的數(shù)據(jù)庫驅(qū)動類名放到配置文件中(常用的有XML文件、Properties文件和文本文件),然后在程序中加載驅(qū)動,來實(shí)現(xiàn)對數(shù)據(jù)庫的解耦,也就是說只要修改配置文件,就可以方便地更改數(shù)據(jù)庫類型。
例如, Spring使用如下的bean配置:
<bean class="com.programcreek.Foo" id="someID"> <property name="someField" value="someValue"> </property></bean>
當(dāng)Spring在處理時,會使用Class.forName(String),同時參數(shù)為"com.xxx.Foo"用于實(shí)例化這個Class。同時,使用反射設(shè)置去用于設(shè)置特定的值。
這種機(jī)制同樣也用于Servlet的web應(yīng)用:
<code><code><code><code><code><code><servlet> <servlet name="">someServlet <servlet>com.programcreek.WhyReflectionServlet</servlet> <servlet data-filtered="filtered"></servlet></servlet></servlet></code></code></code></code></code></code>
三、反射API
Java反射相關(guān)類
Java反射所需要的類并不多,主要有java.lang.Class類java.lang.reflect包中的Field、Constructor、Method、Array類,簡單說明如下所示:
Class類:Class類的實(shí)例表示正在運(yùn)行的Java應(yīng)用程序中的類和接口。Field類:提供有關(guān)類或接口的屬性的信息,以及對它的動態(tài)訪問權(quán)限。反射的字段可能是一個類屬性或?qū)嵗龑傩?,簡單的理解可以把它看成一個封裝反射類的屬性的類。Constructor類:提供關(guān)于類的單個構(gòu)造方法的信息以及對它的訪問權(quán)限。這個類和Field類不同,F(xiàn)ield類封裝了反射類的屬性,而Constructor類則封裝了反射類的構(gòu)造方法。Method類:提供關(guān)于類或接口上單獨(dú)某個方法的信息。所反映的方法可能是類方法或?qū)嵗椒ǎòǔ橄蠓椒ǎ?。這個類不難理解,它是用來封裝反射類方法的一個類。Array類:提供了動態(tài)創(chuàng)建數(shù)組和訪問數(shù)組的靜態(tài)方法。該類中的所有方法都是靜態(tài)方法。
Class
類是程序的一部分,每個類都有一個Class對象。換言之,每當(dāng)編寫并且編譯了一個新類,就會產(chǎn)生一個Class對象。
Class沒有公共構(gòu)造方法。Class對象是在加載類時由Java虛擬機(jī)以及通過調(diào)用類加載器中的defineClass方法自動構(gòu)造的,因此不能顯式地聲明一個Class對象
Class是Reflection的起源。要想操縱;類的屬性和方法,都必須從獲取ClassObject開始。
Class的方法
getName():獲得類的完整名字。getFields():獲得類的public類型的屬性。getDeclaredFields():獲得類的所有屬性。getMethods():獲得類的public類型的方法。getDeclaredMethods():獲得類的所有方法。getMethod(Stringname,Class[]parameterTypes):獲得類的特定方法,name參數(shù)指定方法的名字,–parameterTypes參數(shù)指定方法的參數(shù)類型。getConstrutors():獲得類的public類型的構(gòu)造方法。getConstrutor(Class[]parameterTypes):獲得類的特定構(gòu)造方法,parameterTypes參數(shù)指定構(gòu)造方法的參數(shù)類型。newInstance():通過類的不帶參數(shù)的構(gòu)造方法創(chuàng)建這個類的一個對象。
Constructor
獲得類的構(gòu)造方法
ConstructorgetConstructor(Class[]params)–獲得使用特殊的參數(shù)類型的公共構(gòu)造函數(shù)Constructor[]getConstructors()–獲得類的所有公共構(gòu)造函數(shù)ConstructorgetDeclaredConstructor(Class[]params)–獲得使用特定參數(shù)類型的構(gòu)造函數(shù)(與接入級別無關(guān))Constructor[]getDeclaredConstructors()–獲得類的所有構(gòu)造函數(shù)(與接入級別無關(guān))
Field
獲取類定義變量
FieldgetField(Stringname)–獲得命名的公共字段Field[]getFields()–獲得類的所有公共字段FieldgetDeclaredField(Stringname)–獲得類聲明的命名的字段Field[]getDeclaredFields()–獲得類聲明的所有字段
Method
獲取類定義方法
MethodgetMethod(Stringname,Class[]params)–使用特定的參數(shù)類型,獲得命名的公共方法Method[]getMethods()–獲得類的所有公共方法MethodgetDeclaredMethod(Stringname,Class[]params)–使用特寫的參數(shù)類型,獲得類聲明的命名的方法Method[]getDeclaredMethods()–獲得類聲明的所有方法
四、反射怎么用?
上一章我們講解了Java反射API,那么這一章我們將用一些代碼實(shí)例來展示如何使用這些反射API。
Example1:從對象中獲取類名
package com.longluo.java.interview.reflection; public class ReflectionHelloWorld { public static void main(String[] args) { Foo f = new Foo(); System.out.println(f.getClass().getName()); } } class Foo { public void print() { System.out.println("abc"); } }
輸出:
com.longluo.java.interview.reflection.Foo
Example 2: 調(diào)用未知對象的方法
想象我們不知道一個對象的類型,但是通過反射,我們可以使用這個對象并且找到這個對象是否有個方法名叫print并且調(diào)用它,如下所示:
package com.longluo.java.interview.reflection; import java.lang.reflect.Method; public class ReflectionHelloWorld { /* * public static void main(String[] args) { Foo f = new Foo(); * System.out.println(f.getClass().getName()); } */ public static void main(String[] args) { Foo f = new Foo(); Method method; try { method = f.getClass().getMethod("print", new Class<!--?-->[0]); method.invoke(f); } catch (Exception e) { e.printStackTrace(); } } } class Foo { public void print() { System.out.println("abc"); } }
輸出:
abc
Example 3: 從Class實(shí)例創(chuàng)建對象
package com.longluo.java.interview.reflection; import java.lang.reflect.Method; public class ReflectionHelloWorld { public static void main(String[] args) { // create instance of "Class" Class<!--?--> c = null; try { c = Class.forName("com.longluo.java.interview.reflection.Foo"); } catch (Exception e) { e.printStackTrace(); } // create instance of "Foo" Foo f = null; try { f = (Foo) c.newInstance(); } catch (Exception e) { e.printStackTrace(); } f.print(); } } class Foo { public void print() { System.out.println("abc"); } }
Example 4: 獲取構(gòu)造器并創(chuàng)建實(shí)例
package com.longluo.java.interview.reflection; import java.lang.reflect.Constructor; public class ReflectionHelloWorld4 { public static void main(String[] args) { // create instance of "Class" Class<!--?--> c = null; try { c = Class.forName("com.longluo.java.interview.reflection.Foo4"); } catch (Exception e) { e.printStackTrace(); } // create instance of "Foo" Foo4 f1 = null; Foo4 f2 = null; // get all constructors Constructor<!--?--> cons[] = c.getConstructors(); try { f1 = (Foo4) cons[0].newInstance(); f2 = (Foo4) cons[1].newInstance("abc"); } catch (Exception e) { e.printStackTrace(); } f1.print(); f2.print(); } } class Foo4 { String s; public Foo4() { } public Foo4(String s) { this.s = s; } public void print() { System.out.println(s); } }
輸出:
null abc
另外,你可以使用Class實(shí)例并獲取實(shí)現(xiàn)的接口,父類,聲明的方法等。
Example 5: 通過反射修改數(shù)組大小
package com.longluo.java.interview.reflection; import java.lang.reflect.Array; public class ReflectionHelloWorld5 { public static void main(String[] args) { int[] intArray = { 1, 2, 3, 4, 5 }; int[] newIntArray = (int[]) changeArraySize(intArray, 10); print(newIntArray); String[] atr = { "a", "b", "c", "d", "e" }; String[] str1 = (String[]) changeArraySize(atr, 10); print(str1); } // change array size public static Object changeArraySize(Object obj, int len) { Class<!--?--> arr = obj.getClass().getComponentType(); Object newArray = Array.newInstance(arr, len); // do array copy int co = Array.getLength(obj); System.arraycopy(obj, 0, newArray, 0, co); return newArray; } // print public static void print(Object obj) { Class<!--?--> c = obj.getClass(); if (!c.isArray()) { return; } System.out.println("\nArray length:" + Array.getLength(obj)); for (int i = 0; i < Array.getLength(obj); i++) { System.out.print(Array.get(obj, i) + " "); } } }
輸出:
Array length:10 1 2 3 4 5 0 0 0 0 0 Array length:10 a b c d e null null null null null
五、 總結(jié)
本文只是對Java反射很小的內(nèi)容進(jìn)行了講解,大家有興趣了解更多信息可以從網(wǎng)絡(luò)查找資料。
以上就是本文關(guān)于Java反射簡易教程的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:關(guān)于Java反射機(jī)制 你需要知道的事情、Java的RTTI和反射機(jī)制代碼分析等,有什么問題可以隨時留言,小編會及時回復(fù)大家的。感謝朋友們對本站的支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。