JAVA中的反射機(jī)制(內(nèi)含大量實(shí)例)_第1頁
JAVA中的反射機(jī)制(內(nèi)含大量實(shí)例)_第2頁
JAVA中的反射機(jī)制(內(nèi)含大量實(shí)例)_第3頁
JAVA中的反射機(jī)制(內(nèi)含大量實(shí)例)_第4頁
JAVA中的反射機(jī)制(內(nèi)含大量實(shí)例)_第5頁
已閱讀5頁,還剩14頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。這一概念的提出很快引發(fā)了計(jì)算機(jī)科學(xué)領(lǐng)域關(guān)于應(yīng)用反射性的研究。它首先被程序語言的設(shè)計(jì)領(lǐng)域所采用,并在Lisp和面向?qū)ο蠓矫嫒〉昧顺煽?jī)。其中LEAD/LEAD+ 、OpenC+ 、MetaXa和OpenJava等就是基于反射機(jī)制的語言。最近,反射機(jī)制也被應(yīng)用到了視窗系統(tǒng)、操作系統(tǒng)和文件系統(tǒng)中。 反射本身并不是一個(gè)新概念,它可能會(huì)使我們聯(lián)想到光學(xué)中的反射概念,盡管計(jì)算機(jī)科學(xué)賦予了反射概念新的含義,但是,從現(xiàn)象上來說,它們確實(shí)有某些相通之處,這些有助于我們的理解。在計(jì)算機(jī)科學(xué)領(lǐng)域,反射是指一類應(yīng)

2、用,它們能夠自描述和自控制。也就是說,這類應(yīng)用通過采用某種機(jī)制來實(shí)現(xiàn)對(duì)自己行為的描述(self-representation)和監(jiān)測(cè)(examination),并能根據(jù)自身行為的狀態(tài)和結(jié)果,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語義??梢钥闯觯话愕姆瓷涓拍钕啾?,計(jì)算機(jī)科學(xué)領(lǐng)域的反射不單單指反射本身,還包括對(duì)反射結(jié)果所采取的措施。所有采用反射機(jī)制的系統(tǒng)(即反射系統(tǒng))都希望使系統(tǒng)的實(shí)現(xiàn)更開放??梢哉f,實(shí)現(xiàn)了反射機(jī)制的系統(tǒng)都具有開放性,但具有開放性的系統(tǒng)并不一定采用了反射機(jī)制,開放性是反射系統(tǒng)的必要條件。一般來說,反射系統(tǒng)除了滿足開放性條件外還必須滿足原因連接(Causally-connecte

3、d)。所謂原因連接是指對(duì)反射系統(tǒng)自描述的改變能夠立即反映到系統(tǒng)底層的實(shí)際狀態(tài)和行為上的情況,反之亦然。開放性和原因連接是反射系統(tǒng)的兩大基本要素。 Java中,反射是一種強(qiáng)大的工具。它使您能夠創(chuàng)建靈活的代碼,這些代碼可以在運(yùn)行時(shí)裝配,無需在組件之間進(jìn)行源代表鏈接。反射允許我們?cè)诰帉懪c執(zhí)行時(shí),使我們的程序代碼能夠接入裝載到JVM中的類的內(nèi)部信息,而不是源代碼中選定的類協(xié)作的代碼。這使反射成為構(gòu)建靈活的應(yīng)用的主要工具。但需注意的是:如果使用不當(dāng),反射的成本很高。 二、Java中的類反射: Reflection 是 Java 程序開發(fā)語言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說

4、“自審”,并能直接操作程序的內(nèi)部屬性。Java 的這一能力在實(shí)際應(yīng)用中也許用得不是很多,但是在其它的程序設(shè)計(jì)語言中根本就不存在這一特性。例如,Pascal、C 或者 C+ 中就沒有辦法在程序中獲得函數(shù)定義相關(guān)的信息。 1檢測(cè)類: 1.1 reflection的工作機(jī)制 考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看 reflection 是如何工作的。 import java.lang.reflect.*; public class DumpMethods public static void main(String args) try Class c = Class.forName(args0); Me

5、thod m = c.getDeclaredMethods(); for (int i = 0; i < m.length; i+) System.out.println(mi.toString(); catch (Throwable e) System.err.println(e); 按如下語句執(zhí)行: java DumpMethods java.util.Stack 它的結(jié)果輸出為: public java.lang.Object java.util.Stack.push(java.lang.Object) public synchronized java.lang.Object ja

6、va.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object) 這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。 這個(gè)程序使用 Class.forName 載入指定的類,然后調(diào)用 getDeclaredMethods 來獲取這個(gè)類中定義了的方法列表。java.

7、lang.reflect.Methods 是用來描述某個(gè)類中單個(gè)方法的一個(gè)類。 1.2 Java類反射中的主要方法 對(duì)于以下三類組件中的任何一類來說 - 構(gòu)造函數(shù)、字段和方法 - java.lang.Class 提供四種獨(dú)立的反射調(diào)用,以不同的方式來獲得信息。調(diào)用都遵循一種標(biāo)準(zhǔn)格式。以下是用于查找構(gòu)造函數(shù)的一組反射調(diào)用: l Constructor getConstructor(Class params) - 獲得使用特殊的參數(shù)類型的公共構(gòu)造函數(shù), l Constructor getConstructors() - 獲得類的所有公共構(gòu)造函數(shù) l Constructor getDeclaredC

8、onstructor(Class params) - 獲得使用特定參數(shù)類型的構(gòu)造函數(shù)(與接入級(jí)別無關(guān)) l Constructor getDeclaredConstructors() - 獲得類的所有構(gòu)造函數(shù)(與接入級(jí)別無關(guān)) 獲得字段信息的Class 反射調(diào)用不同于那些用于接入構(gòu)造函數(shù)的調(diào)用,在參數(shù)類型數(shù)組中使用了字段名: l Field getField(String name) - 獲得命名的公共字段 l Field getFields() - 獲得類的所有公共字段 l Field getDeclaredField(String name) - 獲得類聲明的命名的字段 l Field g

9、etDeclaredFields() - 獲得類聲明的所有字段 用于獲得方法信息函數(shù): l Method getMethod(String name, Class params) - 使用特定的參數(shù)類型,獲得命名的公共方法 l Method getMethods() - 獲得類的所有公共方法 l Method getDeclaredMethod(String name, Class params) - 使用特寫的參數(shù)類型,獲得類聲明的命名的方法 l Method getDeclaredMethods() - 獲得類聲明的所有方法 1.3開始使用 Reflection: 用于 reflectio

10、n 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類的 java.lang.Class 對(duì)象。在運(yùn)行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。 下面就是獲得一個(gè) Class 對(duì)象的方法之一: Class c = Class.forName("java.lang.String"); 這條語句得到一個(gè) String 類的類對(duì)象。還有另一種方法,如下面的語句: Class c = int.class; 或者 Class c = Integer.TYPE;

11、 它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預(yù)先定義好的 TYPE 字段。 第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。 一旦取得這個(gè)信息,就可以進(jìn)行第三步了使用 reflection API 來操作這些信息,如下面這段代碼: Class c = Class.forName("java.lang.String"); Method m = c.getDeclaredMethods(); System.out.println(m0.toString(); 它將以文本方式打

12、印出 String 中定義的第一個(gè)方法的原型。 2處理對(duì)象: 如果要作一個(gè)開發(fā)工具像debugger之類的,你必須能發(fā)現(xiàn)filed values,以下是三個(gè)步驟: a.創(chuàng)建一個(gè)Class對(duì)象 b.通過getField 創(chuàng)建一個(gè)Field對(duì)象 c.調(diào)用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對(duì)象就省略;Object是指實(shí)例). 例如: import java.lang.reflect.*; import java.awt.*; class SampleGet public static void main(String args) Rectangle r

13、 = new Rectangle(100, 325); printHeight(r); static void printHeight(Rectangle r) Field heightField; Integer heightValue; Class c = r.getClass(); try heightField = c.getField("height"); heightValue = (Integer) heightField.get(r); System.out.println("Height: " + heightValue.toStrin

14、g(); catch (NoSuchFieldException e) System.out.println(e); catch (SecurityException e) System.out.println(e); catch (IllegalAccessException e) System.out.println(e); 三、安全性和反射: 在處理反射時(shí)安全性是一個(gè)較復(fù)雜的問題。反射經(jīng)常由框架型代碼使用,由于這一點(diǎn),我們可能希望框架能夠全面接入代碼,無需考慮常規(guī)的接入限制。但是,在其它情況下,不受控制的接入會(huì)帶來嚴(yán)重的安全性風(fēng)險(xiǎn),例如當(dāng)代碼在不值得信任的代碼共享的環(huán)境中運(yùn)行時(shí)。 由于這

15、些互相矛盾的需求,Java編程語言定義一種多級(jí)別方法來處理反射的安全性?;灸J绞菍?duì)反射實(shí)施與應(yīng)用于源代碼接入相同的限制: n 從任意位置到類公共組件的接入 n 類自身外部無任何到私有組件的接入 n 受保護(hù)和打包(缺省接入)組件的有限接入 不過至少有些時(shí)候,圍繞這些限制還有一種簡(jiǎn)單的方法。我們可以在我們所寫的類中,擴(kuò)展一個(gè)普通的基本類java.lang.reflect.AccessibleObject 類。這個(gè)類定義了一種setAccessible方法,使我們能夠啟動(dòng)或關(guān)閉對(duì)這些類中其中一個(gè)類的實(shí)例的接入檢測(cè)。唯一的問題在于如果使用了安全性管理器,它將檢測(cè)正在關(guān)閉接入檢測(cè)的代碼是否許可了這樣做

16、。如果未許可,安全性管理器拋出一個(gè)例外。 下面是一段程序,在TwoString 類的一個(gè)實(shí)例上使用反射來顯示安全性正在運(yùn)行: public class ReflectSecurity public static void main(String args) try TwoString ts = new TwoString("a", "b"); Field field = clas.getDeclaredField("m_s1"); / field.setAccessible(true); System.out.println(&quo

17、t;Retrieved value is " + field.get(inst); catch (Exception ex) ex.printStackTrace(System.out); 如果我們編譯這一程序時(shí),不使用任何特定參數(shù)直接從命令行運(yùn)行,它將在field .get(inst)調(diào)用中拋出一個(gè)IllegalAccessException異常。如果我們不注釋field.setAccessible(true)代碼行,那么重新編譯并重新運(yùn)行該代碼,它將編譯成功。最后,如果我們?cè)诿钚刑砑恿薐VM參數(shù)-Djava.security.manager以實(shí)現(xiàn)安全性管理器,它仍然將不能通過編

18、譯,除非我們定義了ReflectSecurity類的許可權(quán)限。 四、反射性能: 反射是一種強(qiáng)大的工具,但也存在一些不足。一個(gè)主要的缺點(diǎn)是對(duì)性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于只直接執(zhí)行相同的操作。 下面的程序是字段接入性能測(cè)試的一個(gè)例子,包括基本的測(cè)試方法。每種方法測(cè)試字段接入的一種形式 - accessSame 與同一對(duì)象的成員字段協(xié)作,accessOther 使用可直接接入的另一對(duì)象的字段,accessReflection 使用可通過反射接入的另一對(duì)象的字段。在每種情況下,方法執(zhí)行相同的計(jì)算 - 循環(huán)中簡(jiǎn)單的加/

19、乘順序。 程序如下: public int accessSame(int loops) m_value = 0; for (int index = 0; index < loops; index+) m_value = (m_value + ADDITIVE_VALUE) * MULTIPLIER_VALUE; return m_value; public int accessReference(int loops) TimingClass timing = new TimingClass(); for (int index = 0; index < loops; index+)

20、timing.m_value = (timing.m_value + ADDITIVE_VALUE) * MULTIPLIER_VALUE; return timing.m_value; public int accessReflection(int loops) throws Exception TimingClass timing = new TimingClass(); try Field field = TimingClass.class. getDeclaredField("m_value"); for (int index = 0; index < loo

21、ps; index+) int value = (field.getInt(timing) + ADDITIVE_VALUE) * MULTIPLIER_VALUE; field.setInt(timing, value); return timing.m_value; catch (Exception ex) System.out.println("Error using reflection"); throw ex; 在上面的例子中,測(cè)試程序重復(fù)調(diào)用每種方法,使用一個(gè)大循環(huán)數(shù),從而平均多次調(diào)用的時(shí)間衡量結(jié)果。平均值中不包括每種方法第一次調(diào)用的時(shí)間,因此初始化時(shí)間不是結(jié)果

22、中的一個(gè)因素。下面的圖清楚的向我們展示了每種方法字段接入的時(shí)間: 圖 1:字段接入時(shí)間 : 我們可以看出:在前兩副圖中(Sun JVM),使用反射的執(zhí)行時(shí)間超過使用直接接入的1000倍以上。通過比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長(zhǎng)700倍以上的時(shí)間。任何JVM上其它兩種方法之間時(shí)間方面無任何顯著差異,但I(xiàn)BM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專業(yè)優(yōu)化,它在簡(jiǎn)單基準(zhǔn)方面表現(xiàn)得很糟糕。反射性能是Sun開發(fā)1.4 JVM時(shí)關(guān)注的一個(gè)方面,它在反射方法調(diào)用結(jié)果中顯示。在這類操作的性能方面,Sun 1.4.1 JV

23、M顯示了比1.3.1版本很大的改進(jìn)。 如果為為創(chuàng)建使用反射的對(duì)象編寫了類似的計(jì)時(shí)測(cè)試程序,我們會(huì)發(fā)現(xiàn)這種情況下的差異不象字段和方法調(diào)用情況下那么顯著。使用newInstance()調(diào)用創(chuàng)建一個(gè)簡(jiǎn)單的java.lang.Object實(shí)例耗用的時(shí)間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創(chuàng)建一個(gè)數(shù)組耗用的時(shí)間是任何測(cè)試的JVM上使用new typesize的兩倍,隨著數(shù)組大小的增加,差異逐步縮小。 結(jié)束語: Java語言反射提

24、供一種動(dòng)態(tài)鏈接程序組件的多功能方法。它允許程序創(chuàng)建和控制任何類的對(duì)象(根據(jù)安全性限制),無需提前硬編碼目標(biāo)類。這些特性使得反射特別適用于創(chuàng)建以非常普通的方式與對(duì)象協(xié)作的庫。例如,反射經(jīng)常在持續(xù)存儲(chǔ)對(duì)象為數(shù)據(jù)庫、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使類和數(shù)據(jù)結(jié)構(gòu)能按名稱動(dòng)態(tài)檢索相關(guān)信息,并允許在運(yùn)行著的程序中操作這些信息。Java 的這一特性非常強(qiáng)大,并且是其它一些常用語言,如 C、C+、Fortran 或者 Pascal 等都不具備的。 但反射有兩個(gè)缺點(diǎn)。第一個(gè)是性能問題。用于字段和方法接入時(shí)反射要遠(yuǎn)慢于直接代碼。性能問題的程度取決于程序中是如何使用反

25、射的。如果它作為程序運(yùn)行中相對(duì)很少涉及的部分,緩慢的性能將不會(huì)是一個(gè)問題。即使測(cè)試中最壞情況下的計(jì)時(shí)圖顯示的反射操作只耗用幾微秒。僅反射在性能關(guān)鍵的應(yīng)用的核心邏輯中使用時(shí)性能問題才變得至關(guān)重要。 許多應(yīng)用中更嚴(yán)重的一個(gè)缺點(diǎn)是使用反射會(huì)模糊程序內(nèi)部實(shí)際要發(fā)生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術(shù)會(huì)帶來維護(hù)問題。反射代碼比相應(yīng)的直接代碼更復(fù)雜,正如性能比較的代碼實(shí)例中看到的一樣。解決這些問題的最佳方案是保守地使用反射僅在它可以真正增加靈活性的地方記錄其在目標(biāo)類中的使用。 最近在成都寫一個(gè)移動(dòng)增值項(xiàng)目,俺負(fù)責(zé)后臺(tái)server端。功能很簡(jiǎn)單,手機(jī)用戶通過GPRS打開So

26、cket與服務(wù)器連接,我則根據(jù)用戶傳過來的數(shù)據(jù)做出響應(yīng)。做過類似項(xiàng)目的兄弟一定都知道,首先需要定義一個(gè)類似于MSNP的通訊協(xié)議,不過今天的話題是如何把這個(gè)系統(tǒng)設(shè)計(jì)得具有高度的擴(kuò)展性。由于這個(gè)項(xiàng)目本身沒有進(jìn)行過較為完善的客戶溝通和需求分析,所以以后肯定會(huì)有很多功能上的擴(kuò)展,通訊協(xié)議肯定會(huì)越來越龐大,而我作為一個(gè)不那么勤快的人,當(dāng)然不想以后再去修改寫好的程序,所以這個(gè)項(xiàng)目是實(shí)踐面向?qū)ο笤O(shè)計(jì)的好機(jī)會(huì)。 首先定義一個(gè)接口來隔離類: package org.bromon.reflect; public interface Operator public java.util.List act(java.u

27、til.List params) 根據(jù)設(shè)計(jì)模式的原理,我們可以為不同的功能編寫不同的類,每個(gè)類都繼承Operator接口,客戶端只需要針對(duì)Operator接口編程就可以避免很多麻煩。比如這個(gè)類: package org.bromon.reflect.*; public class Success implements Operator public java.util.List act(java.util.List params) List result=new ArrayList();Java 的反射機(jī)制是使其具有動(dòng)態(tài)特性的非常關(guān)鍵的一種機(jī)制,也是在JavaBean 中廣泛應(yīng)用的一種特性。

28、運(yùn)用JavaBean 的最常見的問題是:根據(jù)指定的類名,類字段名和所對(duì)應(yīng)的數(shù)據(jù),得到該類的實(shí)例,下面的一個(gè)例子演示了這一實(shí)現(xiàn)。 -|Base.java /抽象基類 |Son1.java /基類擴(kuò)展1 |Son2.java /基類擴(kuò)展2 |Util.java /* * author metaphy * create 2005-4-14 9:06:56 * 說明: */ (1)Base.java 抽象基類只是一個(gè)定義 public abstract class Base (2)Son1.java /Son2.java 是已經(jīng)實(shí)現(xiàn)的JavaBean public class Son1 extends

29、 Base private int id ; private String name ; public int getId() return id; public void setId(int id) this.id = id; public String getName() return name; public void setName(String name) = name; public void son1Method(String s) System.out.println(s) ; (3) public class Son2 extends Base priva

30、te int id; private double salary; public int getId() return id; public void setId(int id) this.id = id; public double getSalary() return salary; public void setSalary(double salary) this.salary = salary; (4)Util.java 演示了如何根據(jù)指定的類名,類字段名和所對(duì)應(yīng)的數(shù)據(jù),得到一個(gè)類的實(shí)例 import java.lang.reflect.Method; public class Uti

31、l /此方法的最大好處是沒有類名Son1,Son2 可以通過參數(shù)來指定,程序里面根本不用出現(xiàn) public static Base convertStr2ServiceBean(String beanName,String fieldSetter,String paraValue) Base base = null ; try Class cls = Class.forName(beanName) ; base = (Base)cls.newInstance() ; Class paraTypes = new ClassString.class ; Method method = cls.ge

32、tMethod(fieldSetter, paraTypes) ; String paraValues = new StringparaValue ; method.invoke(base, paraValues) ; catch (Throwable e) System.err.println(e); return base ; public static void main(String args) Son1 son1 =(Son1) Util.convertStr2ServiceBean("trying.reflect.Son1","setName"

33、;,"wang da sha"); System.out.println("son1.getName() :"+son1.getName() ; /調(diào)用結(jié)果: /son1.getName() :wang da sha 謝謝!希望能給大家一點(diǎn)啟發(fā)! 附: /下面這篇文檔來源于Internet,作者不詳 Reflection 是 Java 程序開發(fā)語言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說“自審”,并能直接操作程序的內(nèi)部屬性。例如,使用它能獲得 Java 類中各成員的名稱并顯示出來。 Java 的這一能力在實(shí)際應(yīng)用中也許用得不是很多

34、,但是在其它的程序設(shè)計(jì)語言中根本就不存在這一特性。例如,Pascal、C 或者 C+ 中就沒有辦法在程序中獲得函數(shù)定義相關(guān)的信息。 JavaBean 是 reflection 的實(shí)際應(yīng)用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動(dòng)態(tài)的載入并取得 Java 組件(類) 的屬性。 1. 一個(gè)簡(jiǎn)單的例子 考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看 reflection 是如何工作的。 import java.lang.reflect.*; public class DumpMethods public static void main(String args) try C

35、lass c = Class.forName(args0); Method m = c.getDeclaredMethods(); for (int i = 0; i < m.length; i+) System.out.println(mi.toString(); catch (Throwable e) System.err.println(e); 按如下語句執(zhí)行: java DumpMethods java.util.Stack 它的結(jié)果輸出為: public java.lang.Object java.util.Stack.push(java.lang.Object) public

36、 synchronized java.lang.Object java.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object) 這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。 這個(gè)程序使用 Class.forName 載入指定的類,然后調(diào)用 getDecl

37、aredMethods 來獲取這個(gè)類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個(gè)類中單個(gè)方法的一個(gè)類。 2.開始使用 Reflection 用于 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類的 java.lang.Class 對(duì)象。在運(yùn)行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。 下面就是獲得一個(gè) Class 對(duì)象的方法之一: Class c = Class.forName("java.la

38、ng.String"); 這條語句得到一個(gè) String 類的類對(duì)象。還有另一種方法,如下面的語句: Class c = int.class; 或者 Class c = Integer.TYPE; 它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預(yù)先定義好的 TYPE 字段。 第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。 一旦取得這個(gè)信息,就可以進(jìn)行第三步了使用 reflection API 來操作這些信息,如下面這段代碼: Class c = Class.forName("

39、;java.lang.String"); Method m = c.getDeclaredMethods(); System.out.println(m0.toString(); 它將以文本方式打印出 String 中定義的第一個(gè)方法的原型。 在下面的例子中,這三個(gè)步驟將為使用 reflection 處理特殊應(yīng)用程序提供例證。 模擬 instanceof 操作符 得到類信息之后,通常下一個(gè)步驟就是解決關(guān)于 Class 對(duì)象的一些基本的問題。例如,Class.isInstance 方法可以用于模擬 instanceof 操作符: class A public class instanc

40、e1 public static void main(String args) try Class cls = Class.forName("A"); boolean b1 = cls.isInstance(new Integer(37); System.out.println(b1); boolean b2 = cls.isInstance(new A(); System.out.println(b2); catch (Throwable e) System.err.println(e); 在這個(gè)例子中創(chuàng)建了一個(gè) A 類的 Class 對(duì)象,然后檢查一些對(duì)象是否是 A 的

41、實(shí)例。Integer(37) 不是,但 new A() 是。 3.找出類的方法 找出一個(gè)類中定義了些什么方法,這是一個(gè)非常有價(jià)值也非?;A(chǔ)的 reflection 用法。下面的代碼就實(shí)現(xiàn)了這一用法: import java.lang.reflect.*; public class method1 private int f1(Object p, int x) throws NullPointerException if (p = null) throw new NullPointerException(); return x; public static void main(String ar

42、gs) try Class cls = Class.forName("method1"); Method methlist = cls.getDeclaredMethods(); for (int i = 0; i < methlist.length; i+) Method m = methlisti; System.out.println("name = " + m.getName(); System.out.println("decl class = " + m.getDeclaringClass(); Class pvec

43、 = m.getParameterTypes(); for (int j = 0; j < pvec.length; j+) System.out.println("param #" + j + " " + pvecj); Class evec = m.getExceptionTypes(); for (int j = 0; j < evec.length; j+) System.out.println("exc #" + j + " " + evecj); System.out.println(&qu

44、ot;return type = " + m.getReturnType(); System.out.println("-"); catch (Throwable e) System.err.println(e); 這個(gè)程序首先取得 method1 類的描述,然后調(diào)用 getDeclaredMethods 來獲取一系列的 Method 對(duì)象,它們分別描述了定義在類中的每一個(gè)方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 來代替 getDeclaredMethods,

45、你還能獲得繼承來的各個(gè)方法的信息。 取得了 Method 對(duì)象列表之后,要顯示這些方法的參數(shù)類型、異常類型和返回值類型等就不難了。這些類型是基本類型還是類類型,都可以由描述類的對(duì)象按順序給出。 輸出的結(jié)果如下: name = f1 decl class = class method1 param #0 class java.lang.Object param #1 int exc #0 class java.lang.NullPointerException return type = int - name = main decl class = class method1 param #0

46、class Ljava.lang.String; return type = void - 4.獲取構(gòu)造器信息 獲取類構(gòu)造器的用法與上述獲取方法的用法類似,如: import java.lang.reflect.*; public class constructor1 public constructor1() protected constructor1(int i, double d) public static void main(String args) try Class cls = Class.forName("constructor1"); Construct

47、or ctorlist = cls.getDeclaredConstructors(); for (int i = 0; i < ctorlist.length; i+) Constructor ct = ctorlisti; System.out.println("name = " + ct.getName(); System.out.println("decl class = " + ct.getDeclaringClass(); Class pvec = ct.getParameterTypes(); for (int j = 0; j &l

48、t; pvec.length; j+) System.out.println("param #" + j + " " + pvecj); Class evec = ct.getExceptionTypes(); for (int j = 0; j < evec.length; j+) System.out.println("exc #" + j + " " + evecj); System.out.println("-"); catch (Throwable e) System.err.p

49、rintln(e); 這個(gè)例子中沒能獲得返回類型的相關(guān)信息,那是因?yàn)闃?gòu)造器沒有返回類型。 這個(gè)程序運(yùn)行的結(jié)果是: name = constructor1 decl class = class constructor1 - name = constructor1 decl class = class constructor1 param #0 int param #1 double - 5.獲取類的字段(域) 找出一個(gè)類中定義了哪些數(shù)據(jù)字段也是可能的,下面的代碼就在干這個(gè)事情: import java.lang.reflect.*; public class field1 private dou

50、ble d; public static final int i = 37; String s = "testing" public static void main(String args) try Class cls = Class.forName("field1"); Field fieldlist = cls.getDeclaredFields(); for (int i = 0; i < fieldlist.length; i+) Field fld = fieldlisti; System.out.println("name

51、= " + fld.getName(); System.out.println("decl class = " + fld.getDeclaringClass(); System.out.println("type = " + fld.getType(); int mod = fld.getModifiers(); System.out.println("modifiers = " + Modifier.toString(mod); System.out.println("-"); catch (Thro

52、wable e) System.err.println(e); 這個(gè)例子和前面那個(gè)例子非常相似。例中使用了一個(gè)新東西 Modifier,它也是一個(gè) reflection 類,用來描述字段成員的修飾語,如“private int”。這些修飾語自身由整數(shù)描述,而且使用 Modifier.toString 來返回以“官方”順序排列的字符串描述 (如“static”在“final”之前)。這個(gè)程序的輸出是: name = d decl class = class field1 type = double modifiers = private - name = i decl class = class

53、 field1 type = int modifiers = public static final - name = s decl class = class field1 type = class java.lang.String modifiers = - 和獲取方法的情況一下,獲取字段的時(shí)候也可以只取得在當(dāng)前類中申明了的字段信息 (getDeclaredFields),或者也可以取得父類中定義的字段 (getFields) 。 6.根據(jù)方法的名稱來執(zhí)行方法 文本到這里,所舉的例子無一例外都與如何獲取類的信息有關(guān)。我們也可以用 reflection 來做一些其它的事情,比如執(zhí)行一個(gè)指定了

54、名稱的方法。下面的示例演示了這一操作: import java.lang.reflect.*; public class method2 public int add(int a, int b) return a + b; public static void main(String args) try Class cls = Class.forName("method2"); Class partypes = new Class2; partypes0 = Integer.TYPE; partypes1 = Integer.TYPE; Method meth = cls.

55、getMethod("add", partypes); method2 methobj = new method2(); Object arglist = new Object2; arglist0 = new Integer(37); arglist1 = new Integer(47); Object retobj = meth.invoke(methobj, arglist); Integer retval = (Integer) retobj; System.out.println(value(); catch (Throwable e) System.err.println(e); 假如一個(gè)程序在執(zhí)行的某處的時(shí)候才知道需要執(zhí)行某個(gè)方法,這個(gè)方法的名稱是在程序的運(yùn)行過程中指定的 (例如,JavaBean 開發(fā)環(huán)境中就會(huì)做這樣的事),那么上面的程序演示了如何做到。 上例中,getMethod 用于查找一個(gè)具有兩個(gè)整型參數(shù)且名為 add 的方法。找到該方法并創(chuàng)建了相應(yīng)的 Method 對(duì)象之后,在正確的對(duì)象實(shí)例中執(zhí)行它。執(zhí)行該方法的時(shí)候,需要提供一個(gè)參數(shù)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論