




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、摘要Reflection 是Java被視為動態(或準動態)語言的一個關鍵性質。這個機制允許程序 在運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers (諸如 public, static等等)、superclass (例如 Object )、實現之in terfaces(例如Clo neable ),也包括 fields 和methods 的所有信息,并可于運行時改變fields 內容或喚起 methods。本文借由實例,大面積示范Reflection APIs。關于本文:讀者基礎:具備 Java語言基礎本文適用工具:JDK1.5關鍵詞
2、:In trospection(內省、內觀)Reflection (反射)有時候我們說某個語言具有很強的動態性,有時候我們會區分動態和靜態的不同技術與作法。我們朗朗上口動態綁定(dyn amic binding )、動態鏈接(dyn amic linking )、動態加載(dynamic loading)等。然而“動態” 一詞其實沒有絕對而普遍適用的嚴格定義,有時候甚至像對象導向當初被導入編程領域一樣,一人一把號,各吹各的調。一般而言,開發者社群說到動態語言,大致認同的一個定義是:“程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言。從這個觀點看,Perl ,Python ,Ruby
3、是動態語言,C+, Java , C#不是動態語言。盡管在這樣的定義與分類下Java不是動態語言,它卻有著一個非常突岀的動態相關機制:Reflection。這個字的意思是“反射、映象、倒影,用在Java身上指的是我們可以于運行時加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個運行時才得知名稱的 class ,獲悉其完整構造(但不包括methods 定義),并生成其對象實體、或對其fields設值、或喚起其methods 1。這種看透 class 的能力(the ability ofthe program to exam ine itself)被稱為 intr
4、ospection(內省、內觀、反省)。是常被并提的兩個術語。Reflection和口 introspectionJava如何能夠做岀上述的動態特性呢?這是一個深遠話題,本文對此只簡單介紹一些概念。整個篇幅最主要還是介紹ReflectionAPIs,也就是讓讀者知道如何探索class 的結構、如何對某個運行時才獲知名稱的class”生成一份實體、為其fields 設值、調用其methods 。本文將談至U java.lang.Class,以及 java.lang.reflect中的 Method 、FieldCon structor等等 classesClass” class眾所周知Java有
5、個Object class,是所有Java classes的繼承根源,其內聲明了數個應該在所有Java class中被改寫的methods:hashCode()、equals。、clone()toStri ng()、getClass() 等。其中 getClass()返回一個 Class objectJavaClass class十分特殊。它和一般classes一樣繼承自 Object ,其實體用以表達types程序運行時的classes和口 in terfaces,也用來表達 enum、array primitive Java(boolea n, byte, char, short, in
6、t, l ong, float, double)以及關鍵詞void 。當一個class 被加載,或當加載器( class loader )的defineClass()被JVM調用,JVM便自動產生一個Class object。如果您想借由修改 Java標準庫源碼來觀察 Classobject的實際生成時機(例如在Class 的constructor內添加一個println(),不能夠!因為 Class 并沒有 public constructor(見圖1)本文最后我會撥一小塊篇幅順帶談談Java標準庫源碼的改動辦法。Class 是Reflection故事起源。針對任何您想探勘的class,唯有
7、先為它產生一個Class object,接下來才能經由后者喚起為數十多個的Reflection APIs。這些APIs將在稍后的探險活動中一一亮相。#001 public final#002 class Class implements java.io.Serializable,#003 java.la ng.reflect.Ge nericDeclarati on, #004 java.la ng.reflect.Type,#005 java.la ng.reflect.A nno tatedEleme nt #006 private Class() #007 public Stringto
8、String () #008 return ( isInterface() ? interface :#009 (isPrimitive() ? : class )#010 + getName();#011 圖1 : Classclass 片段。注意它的private empty ctor,意指不允許任何人經由編程方式產生Classobject是的,其 object只能由JVM產生。Class” object的取得途徑Java允許我們從多種管道為一個class 生成對應的 Classobject。圖2是一份整理。Class object誕生管道示例運用 getClass()Stri ng st
9、r = abc;注:每個class都有此函數Class c1 = str.getClass();運用Butt on b = new Butt on();Class.getSuperclass()Class c1 = b.getClass();2Class c2 = c1.getSuperclass();運用 static methodClass c1 = Class.forName (java.la ng.Stri ng);Class.forName()Class c2 = Class.forName (java.awt.Butt on);(最常被使用)Class c3 = Class.for
10、Name(java.util.L in kedList$E ntry);Class c4 = Class.forName (I);Class c5 = Class.forName (I);運用Class c1 = Strin g.class;.class 語法Class c2 = java.awt.Butt on. class;Class c3 = Main.lnn erClass.class;Class c4 = in t.class;Class c5 = in t.class;運用Class c1 = Boolea n. TYPE;primitive wrapperClass c2 = B
11、yte.TYPE;classesClass c3 = Character.TYPE;的TYPE語法Class c4 = Short.TYPE;Class c5 = In teger.TYPE;Class c6 = Lo ng.TYPE;Class c7 = Float.TYPE;Class c8 = Double.TYPE;Class c9 = Void.TYPE;圖2 : Java允許多種管道生成 Class object 。Java classes組成分析首先容我以圖3的java.util.LinkedList為例,將Java class的定義大卸八塊,每一塊分別對應 圖4所示的Refle
12、ction API。圖5則是“獲得class各區塊信息”的程序示例及執行結果,它們都取自本文示例程序的對應片段。package java.util;(1)import java.la ng.*;(2)public class LinkedList (3)( 4)(5)extends AbstractSequentialList/(6)implements List , Queue ,Clon eable, java.io.Serializable /(7)private static classEntry /(8)publicLinkedList()(9)publicLinkedList(Co
13、llectionv? extends E c) public EgetFirst()(10)public EgetLast().private transient Entryheader =;private transient intsize = 0;)圖3:將一個 Java class大卸八塊,每塊相應于一個或一組Reflection APIs(圖4)Java classes各成份所對應的 Reflection APIs圖3的各個Java class成份,分別對應于 圖4的Reflection API,其中岀現的 PackageMethod、Con structor 、Field 等等 cl
14、asses,都定義于 java .Ian g.reflect。Java class內Java class內部模塊說相應之 Reflection返回值類型部模塊(參見圖明API,多半為(returntype)3)Classmethods。(1) packageclass 隸屬哪個packagegetPackage()Package(2) importclass 導入哪些classes無直接對應之 API。解決辦法見圖5-2。(3) modifierclass (或 methods,int getModifiers()intfields )的屬性Modifier.toStr ing(Str ing
15、int)boolModifier.isI nterface(i nt)(4) classclass/i nterface名稱 getName()Str ingn ame orin terfacen ame(5) type參數化類型的名稱getTypeParameters(TypeVariableparameters)(6) base classbase class(只可能一個)getSuperClass()Classimpleme ntedin terfaces實現有哪些in terfacesgetI nterfaces()Class(8) inner classes內部 classesget
16、DeclaredClasses()Class(8) outer如果我們觀察的class 本getDeclari ngClass(Classclass身是 inner classes,那么相對它就會有個outer class。)(9)構造函數不論 public 或Con structorcon structorsgetDeclaredC on structors()private或其它access level,皆可獲得。另有功能近似之取得 函數。(10) methods操作函數getDeclaredMethods()不論 public 或private或其它access level,皆可獲得。另
17、有功能近似之取得 函數。Method(11) fields字段(成員變量)getDeclaredFields()不論 public 或 private或其它access level,皆可獲得。另有功能近似之取得 函數。Field圖4 : Java class大卸八塊后(如圖 3),每一塊所對應的 Reflection API。本表并非Reflection APIs的全部。Java Reflection API運用示例圖5示范圖4提過的每一個 Reflection API,及其執行結果。程序中岀現的 tName()是個輔助函數,可將其第一自變量所代表的“Java class完整路徑字符串”剝除路
18、徑部分,留下class 名稱,儲存到第二自變量所代表的一個hashtable去并返回(如果第二自變量為null就不儲存而只是返回)。#001 Class c = null;#002 c = Class.forName (args0);#003#004 Package p;#005 p = c. getPackage ();#006#007 if (p != null)#008 System.out.println(package +p.getName ()+;);執行結果(例)圖5-1 :找出class 隸屬的package。其中的c將繼續沿用于以下各程序片段#001 ff = c. getD
19、eclaredFields ();#002 for (int i = 0; i ff.length; i+)#003 x = tName(ffi.getType().getName(), classRef);#004#005 cn = c. getDeclaredConstructors();#006 for (int i = 0; i cn.length; i+) #007 Class cx = cn i.getParameterTypes();#008 for (int j = 0; j cx.length; j+)#009 x = tName(cxj.getName(), classRe
20、f);#010 #011#012 mm = c. getDeclaredMethods ();#013 for (int i = 0; i mm.length; i+) #014 x = tName(mmi.getRetur nType().getName(), classRef);#015 Class cx = mmi.getParameterTypes();#016 for (int j = 0; j cx.length; j+)#017 x = tName(cxj.getName(), classRef);#018 #019 classRef.remove(c.getName();/不必
21、記錄自己(不需 import 自己)執行結果(例)#004 if ( Modifier.isInterface#005 System.out.print(”); /#006 else#007 System.out.print(” class ); /#008 System.out.print(tName(c.圖5-2 :找出導入的classes,動作細節詳見內文說明#001 int mod = c.getModifiers ();#002 System.out.print(Modifier.toString(mod); / 整個 modifier#003(mod)關鍵詞interface 已含
22、于 modifier關鍵詞 classgetName (), null); /class名稱執行結果(例)圖5-3 :找出class 或interface的名稱,及其屬性( modifiers )tv;#001 TypeVariable #002 tv = c. getTypeParameters (); / warning: unchecked conversion#003 for (int i = 0; i tv.length; i+) #004x = tName(tvi.getName(), null); /例如E,K,V#005if (i = 0) /第一個#006System.out
23、.pri nt();#011 執行結果(例):public abstract interface Map或 public class LinkedList的名稱圖 5-4 :找出 parameterized types#001 Class supClass;#002 supClass = c.getSuperclass ();女口果有 super class#003 if (supClass != null) /#004 System.out.pri nt( exte nds +#005 tName(supClass.getName (),classRef);執行結果(例):public cl
24、ass Lin kedList圖5-5 :找出base class。執行結果多出一個不該有的逗號于尾端。此非本處重點,為簡化計,不多做處理。#001 Class cc;#002 Class ctmp;#003 /找出所有被實現的interfaces#004 cc = c. getInterfaces ();#005 if (cc.le ngth != 0)#006 System.out.print(, rn + implements ); /關鍵詞#007 for (Class cite : cc) /JDK1.5新式循環寫法#008 System.out.print(tName(cite.g
25、etName (), null)+,);執行結果(例):public class Lin kedList exte nds AbstractSeque ntialList,圖5-6 :找出implemented interfaces。執行結果多出一個不該有的逗號于尾端。此非本處重點,為簡化計,不多做處理。#001 cc = c. getDeclaredClasses#002 for (Class cite : cc)#003 System.out.println(tName(cite.#004#005 ctmp = c. getDeclaringClass#006 if (ctmp != nu
26、ll)#007 System.out.println(ctmp.();/ 找出 inner classesgetName (), null);();/ 找出 outer classesgetName ();執行結果(例)圖5-7 :找出 inner classes 和 outer class#001 Constructor cn;#002 cn = c. getDeclaredConstructors();#003 for (int i = 0; i cn.length; i+) #004 int md = cni.getModifiers ();#005 System.out.pri nt(
27、 + Modifier.toStri ng(md) + +#006 cni.getName();#007 Class cx = cni.getParameterTypes ();#008 System.out.pri nt();#009 for (int j = 0; j cx.length; j+) #010System.out.pri nt(tName(cxj.getName(), null);#011 if (j (cx.length - 1) System.out.print(,);#012 #013 System.out.pri nt();#014 執行結果(例)圖 5-8a :找出
28、所有 constructors#004 System.out.println(cni.toGenericString ();執行結果(例)圖5-8b :找出所有 constructors。本例在for 循環內使用toGenericString(),省事。#001 Method mm;#002 mm = c. getDeclaredMethods ();#003 for (int i = 0; i mm.length; i+) #004 int md = mmi.getModifiers ();#005 System.out.pri nt( +Modifier.toStrin g(md)+ +#
29、006 tName(mmi. getReturnType ().getName(), null)+ +#007 mmi.getName();#008 Class cx = mmi.getParameterTypes ();#009 System.out.pri nt();#010 for (int j = 0; j cx.length; j+) #011 System.out.pri nt(tName(cxj.getName(), null);#012 if (j (cx.length - 1) System.out.print(,);#013 #014 System.out.pri nt()
30、;#015 執行結果(例)圖5-9a :找出所有methodstoGenericString ();#004 System.out.println(mmi.圖5-9b :找出所有methods。本例在for 循環內使用toGenericString(),省事。#001 Field ff;#002 ff = c. getDeclaredFields ();#003 for (int i = 0; i ff.length; i+) #004 int md = ffi.getModifiers ();#005 System.out.println(” +Modifier.toString(md)+#
31、006 tName(ffi.getType().getName(), null) + +#007 ffi.getName()+;);#008 執行結果(例)圖5-10a :找出所有fields#004 System.out.pri ntln( G: + ffi.toGe nericStri ng();圖5-10b :找出所有fields 。本例在for循環內使用toGenericString(),省事。找出class 參用(導入)的所有classes沒有直接可用的 Reflection API可以為我們找岀某個class參用的所有其它classes 。要獲得這項信息,必須做苦工,一步一腳印逐一
32、記錄。我們必須觀察所有fields的類型、所有methods (包括constructors)的參數類型和回返類型,剔除重復,留下唯一。這正是為什么圖5-2程序代碼要為tName()指定一個hashtable(而非一個null )做為第二自變量的緣故:hashtable可為我們儲存元素(本例為字符串),又保證不重復。本文討論至此,幾乎可以還原一個 class 的原貌(唯有methods 和ctors 的定義無法取得)。接下來討論 Reflection的另三個動態性質:(1)運行時生成instances, (2)執行期喚起 methods , (3)運行時改動fields 。運行時生成insta
33、nces欲生成對象實體,在 Reflection 動態機制中有兩種作法,一個針對無自變量ctor ”,一個針對“帶參數ctor ”。圖6是面對“無自變量ctor ”的例子。如果欲調用的是“帶參數ctor 就比較麻煩些, 圖7是個例子,其中不再調用 Class 的newInstance(),而是調用Constructor 的newInstance()。圖7首先準備一個 Class 做為ctor 的參數類型(本例指定為一個double 和一個int ),然后以此為自變量調用 getConstructor(),獲得一個專屬ctor 。接下來再準備一個 Object 做為ctor 實參值(本例指定 3
34、.14159和125 ),調用 上述專屬 ctor 的 newlnstance()。#001 Class c = Class.forName(Dy nTest);#002 Object obj = null;#003 obj = c.newInstance (); / 不帶自變量#004 System.out.pr intln (obj);圖6 :動態生成Class object所對應之class 的對象實體;無自變量。#001 Class c = Class.forName(Dy nTest);#002 Class pTypes = new Class double.class, in t.
35、class ;#003 Constructor ctor = c.getConstructor(pTypes);#004 / 指定parameter list,便可獲得特定之 ctor#005#006 Object obj = null;#007 Object arg = new Object 3.14159, 125; /自變量#008 obj = ctor.newInstance (arg);#009 System.out.pr intln (obj);圖7 :動態生成“ Class object 對應之class 的對象實體;自變量以 Object 表示。運行時調用methods這個動作
36、和上述調用帶參數之 ctor ”相當類似。首先準備一個 Class 做為ctor的參數類 型(本例指定其中一個是Stri ng ,另一個是 Hashtable ),然后以此為自變量調用getMethod(),獲得特定的 Methodobject。接下來準備一個Object 放置自變量,然后調用上述所得之特定Methodobject 的invoke() ,如圖8。知道為什么索取 Methodobject時不需指定回返類型嗎?因為 method overloadi ng機制要求sig nature(署名式)必須唯一,而回返類型并非sig nature的一個成份。換句話說,只要指定了method名稱
37、和參數列,就一定指岀了一個獨一無二的method。#001 public Stringfunc (String s, Hashtable ht)#002 #003 System.out.println(func invoked); return s;#004 #005 public static void main(String args)#006 #007 Class c = Class.forName(Test);#008 Class ptypes = new Class2;#009 ptypes0 = Class.forName(java.la ng.Stri ng);#010 ptyp
38、es1 = Class.forName(java.util.Hashtable);#011 Method m = c. getMethod ( func ,ptypes);#012 Test obj = new Test();#013 Object args = new Object2;#014 arg0 = new String(Hello,world);#015 arg1 = null;#016 Object r = m.invoke (obj, arg);#017 In teger rval = (Stri ng)r;#018 System.out.pr intln (rval);#01
39、9 圖8 :動態喚起 method運行時變更fields 內容與先前兩個動作相比,“變更field內容”輕松多了,因為它不需要參數和自變量。首先調用Class 的getField() 并指定field 名稱。獲得特定的 Fieldobject之后便可直接調用Field 的 get() 和 set(),如圖 9。#001 public class Test #002 public doubled;#003#004 public static void main(String args)#005 #006 Class c = Class.forName(Test);#007 Field f = c. getField ( d); / 指定 field 名稱#008 Test obj = new Test();#009 System.out.println(d= +(Double) f.get (obj);#010 f.set (obj, 12.34);
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 學前教育課程研發計劃
- 文化藝術節朗讀活動計劃
- 藝術空間裝修施工質量評估措施
- 小學一年級上冊教師培訓工作計劃
- 2025企業員工崗前安全培訓考試試題答案A卷
- 25年公司主要負責人安全培訓考試試題及參考答案【研優卷】
- 交通標志牌施工合同爭議庭審筆錄3篇
- 戶外廣告牌建設合同3篇
- 廢鐵廢鋼買賣合同書3篇
- 2025年商超貨架合作協議書
- 2024年飯店轉讓合同簡單版(三篇)
- 大數據與會計社會實踐報告
- 小學一二年級必背古詩詞73首帶拼音
- 《陸上風電場工程概算定額》NBT 31010-2019
- 2024年信陽職業技術學院單招職業適應性測試題庫帶答案
- 生物醫學電子學智慧樹知到期末考試答案章節答案2024年天津大學
- 《電磁學》梁燦彬課后答案解析
- 2024年山東省事業單位歷年面試題目及答案解析50套
- 富血小板血漿治療術知情同意書
- Charter開發與立項流程(CDP)
- 中華民族共同體概論課件第三講文明初現與中華民族起源(史前時期)
評論
0/150
提交評論