![Java反射講義_第1頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/10/7da349bb-d6ec-47d7-b2ba-da9835325e15/7da349bb-d6ec-47d7-b2ba-da9835325e151.gif)
![Java反射講義_第2頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/10/7da349bb-d6ec-47d7-b2ba-da9835325e15/7da349bb-d6ec-47d7-b2ba-da9835325e152.gif)
![Java反射講義_第3頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/10/7da349bb-d6ec-47d7-b2ba-da9835325e15/7da349bb-d6ec-47d7-b2ba-da9835325e153.gif)
![Java反射講義_第4頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/10/7da349bb-d6ec-47d7-b2ba-da9835325e15/7da349bb-d6ec-47d7-b2ba-da9835325e154.gif)
![Java反射講義_第5頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/10/7da349bb-d6ec-47d7-b2ba-da9835325e15/7da349bb-d6ec-47d7-b2ba-da9835325e155.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Java中的反射在java中反射的是,我們可以在運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的類。換句話說,Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的類,獲悉其完整結(jié)構(gòu),并生成其對(duì)象實(shí)體、或?qū)ζ渥兞吭O(shè)值、或調(diào)用其方法。這種“看透類”的能力被稱為Introspection(內(nèi)省,內(nèi)觀,反?。eflection和Introspection是常被并提的兩個(gè)術(shù)語。在java中,反射是一種強(qiáng)大的工具。它使你能夠靈活的代碼,這些代碼可以在運(yùn)行時(shí)裝配,無須在組件之前進(jìn)行源代表連接。反射容許我們?cè)诰帉懪c執(zhí)行時(shí),使我們的程序代碼能夠接入轉(zhuǎn)載到JVM中的類的內(nèi)部信息,而不是源代碼中選定的類協(xié)助的代碼。這使反射成為構(gòu)
2、建靈活應(yīng)用的主要工具。但需要注意的是,如果使用不當(dāng),反射的成本很高。Reflection是Java程序開發(fā)語言的特征之一,它允許運(yùn)行的Java程序?qū)ψ陨磉M(jìn)行檢查,或者說“自審”,并能直接操作程序的內(nèi)部屬性。例如,使用它能獲取得Java類中各成員并顯示出來。Java的這一能力在實(shí)際應(yīng)用中也許用的不是很多,但是在其他程序設(shè)計(jì)語言中根本不存在這一特性。例如Pascal、C、C+中就沒有辦法在程序中獲得函數(shù)定義相關(guān)的信息。JavaBean是Reflection的實(shí)際應(yīng)用之一,它能讓一些工具可視化地操作軟件組件。這些工具通過Reflection動(dòng)態(tài)地載入并獲取Java組件(類)的屬性。1、第一個(gè)反射的例
3、子public class Test public static void main(String args) throws Exception Class c= Class.forName("java.lang.System");Method m=c.getDeclaredMethods();for(int i=0;i<m.length;i+)System.out.println(mi);該例子列出了java.lang.Systme類的各方法名及它們的限制符和返回類型。這個(gè)程序使用Class.forName載入指定的類,然后調(diào)用getDeclaredMethods來
4、獲取這個(gè)類中定義了的方法列表。java.lang.reflect.Method是用來描述某個(gè)類中單個(gè)方法的一個(gè)類。2、Java反射APIjava提供了一套獨(dú)特的反射API來描述類,使得Java程序在運(yùn)行時(shí)可以獲得任何一個(gè)類的字節(jié)碼信息,包括類的修飾符(public,static等)、基類(超類,父類)、實(shí)現(xiàn)的接口、字段和方法等信息,并可以根據(jù)字節(jié)碼信息來創(chuàng)建該類的實(shí)例化對(duì)象,改變?cè)搶?duì)象的字段內(nèi)容和調(diào)用該對(duì)象的方法。Class是Java反射中的一個(gè)核心類,它代表了內(nèi)存中的一個(gè)Java類。通過它可以獲取類的各種操作屬性,這些屬性是通過java.lang.reflect包中的反射API來描述的。*C
5、onstructor:用來描述一個(gè)類的構(gòu)造方法。*Field:用來描述一個(gè)類的成員變量*Method:用來描述一個(gè)類的方法*Modifer:用來描述類中各元素的修飾符*Array:用來對(duì)數(shù)組進(jìn)行操作它們之間的關(guān)系如圖26-1對(duì)于任何一類來說,都可以通過Class提供的反射API獲取類信息。除了可以使用newInstance()創(chuàng)建該類的實(shí)例外,可以使用Class取得類的包和類名:Package getPackage(); /獲取此類的包String getName();/獲取此類的類名Class最重要的功能是提供了一組反射調(diào)用,用以獲取構(gòu)造函數(shù),變量及方法。2.1獲取類的構(gòu)造函數(shù)提供了3種方法
6、*獲得類的所有構(gòu)造函數(shù)和方法:Constructor<?> getConstructors(); /當(dāng)前類的構(gòu)造函數(shù)Constouctor<?> getDeclaredConstructors(); /當(dāng)前類的構(gòu)造函數(shù)*獲得使用特殊的參數(shù)類型的公共構(gòu)造函數(shù):Constructor<T> getConstructor(Class<?>.parameterTypes);/當(dāng)前類的構(gòu)造函數(shù)Constructor<T> getDeclaredConstructor(Class<?>.parameterTypes) /當(dāng)前類或接口的
7、構(gòu)造函數(shù)*獲取本地或者匿名類的構(gòu)造函數(shù)Constructor<?> getEnclosingConstructor();Constructor類提供了取得參數(shù)類型和創(chuàng)造實(shí)例的方法Class<?> getParameterTypes();/取得參數(shù)類型T newInstance(Object. initargs); /創(chuàng)建該構(gòu)造方法的聲明類的新實(shí)例2.2 取得變量-返回Field獲得字段信息的Class反射調(diào)用不同于那些用于接入構(gòu)造函數(shù)的調(diào)用,在參數(shù)類型數(shù)組中可以使用字段名。*取得指定名稱的變量:Field getField(String name);/類或接口的指定公共
8、成員字段Field getDeclaredField(String name);/類或接口的指定成員字段*取得類或接口所聲明的所有變量:Field getFields();/類或接口的指定公共成員字段Field getDeclaredFields();/類或接口的指定成員字段Field類為變量提供了獲得或修改值的方法/獲取變量值boolean getBoolean(Object obj);byte getByte(Objcet obj);char getChar(Object obj);double getDouble(Object obj);float getFloat(Object obj
9、);int getInt(Object obj);long getLong(Object obj);short getShort(Object obj);/修改變量值void setBoolean(Object obj,boolean z);void setByte(Object obj,byte b);void setChar(Object obj,char c);void setDouble(Object obj,double d);void setFloat(Object obj,float f);void setInt(Object obj,int i);void setLong(Ob
10、ject obj,long l);void setShort(Object obj,short s);2.3 獲取方法-返回類型Method用于獲得方法信息函數(shù)如下:*使用特定的參數(shù)類型獲取命名的方法Method getMethod(String name,Class<?>. prameterTypes);/類或接口的指定公共成員方法Method getDeclaredMethod(String name,Class<?>. prameterTypes);/類或接口的指定成員方法*獲取所有方法列表Method getMethods(); /類或接口的所有公共成員方法Me
11、thod getDeclaredMethods(); /類或接口的所有成員Method為方法提供了取參數(shù)和返回值類型及調(diào)用的方法:Class<?>getParameterTypes(); /取得參數(shù)類型Class<?>getReturnType();/取得返回值類型Object invoke(Object obj,Object.args); /對(duì)帶有指定參數(shù)的指定對(duì)象調(diào)用方法車2.4 Array類提供了動(dòng)態(tài)創(chuàng)建Java數(shù)組的方法,這些方法對(duì)應(yīng)了8個(gè)Java的基本類型,形如static boolean getBoolean(Object array,int index);
12、static void setBoolean(Object array,int index,boolean z);2.5 Modifier類提供了static方法和常量,對(duì)類和成員訪問修飾符進(jìn)行解碼。修飾符集被表現(xiàn)為整數(shù),用不同的位置(bit position)表示不同的修飾符。static int ABSTRACT;/表示abstract修飾符的int的值static int FINAL;/表示final修飾的int值static int INTERFACE;/表示interface修飾符的int的值static int NARIVE;/表示native修飾符的int的值static int
13、 PRIVATE;/表示private修飾符的int的值static int PUBLIC;/表示public修飾符的int的值static int STATIC;/表示static修飾符的int的值static int STRICT;/表示strictfp修飾符的int的值static int SYNCHRONIZED;/表示synchronized修飾符的int值static int TRANSIENT;/表示transient修飾符的int的值static int VOLATILE; /表示volatile修飾的int值3、Java反射應(yīng)用-檢測(cè)類從上面的API函數(shù)可以看出,Java反射
14、功能能實(shí)現(xiàn)類的查找、創(chuàng)建與調(diào)試。上面的介紹必須抽象,本節(jié)將根據(jù)實(shí)際應(yīng)用的需求來分類講解Java反射的應(yīng)用實(shí)例。為了演示通過代碼對(duì)類的動(dòng)態(tài)加載和調(diào)用,我們首先建立一個(gè)類MyObject,該類用來計(jì)算兩個(gè)數(shù)的加、減、乘、除,供后面演示調(diào)用。public class MyObject private int a,b;public MyObject(int a,int b)this.a=a;this.b=b;int sum()return a+b;private int minus()return a-b;public int multiply()return a*b;int divide()retu
15、rn a/b;該類中包括了變量、構(gòu)造函數(shù)和方法,足夠后面的演示所需。本節(jié)的內(nèi)容包括以下幾項(xiàng)。*獲取類*獲取類的方法*獲取類的構(gòu)造器*獲取類的變量3.1 標(biāo)準(zhǔn)會(huì)話管理器StandardManager在運(yùn)行的Java程序中,用java.lang.Class類來描述類的接口等下面就是獲得Class對(duì)象的方法之一:Class cls = Class.forName("test.MyObject");獲取Class對(duì)象的另外一個(gè)方法:Class cls = MyObject.class;3.2 獲取類的方法找出一個(gè)類中定義了什么方法,這是一個(gè)非常有價(jià)值其基礎(chǔ)的Reflection用法
16、,下面的代碼就是證實(shí)了這一用法。/取得類的方法Method methods=c.getDeclaredMethods();for(Method method:methods)System.out.print("修飾符"+method.getModifiers();System.out.print("方法名"+method.getName();System.out.println("返回值類型"+method.getReturnType();/參數(shù)列表Class params= method.getParameterTypes();fo
17、r(int i=0;i<params.length;i+)System.out.println("參數(shù)"+paramsi);這個(gè)程序調(diào)用getDeclaredMethods()來獲取一系列的Method對(duì)象,它們分別描述了定義中的每一個(gè)方法,包括public方法,protected方法,private方法等。如果你在程序中使用getMethods()來代替getDeclaredMethods(),你還能獲得繼承來的各個(gè)方法的信息。取得了Method對(duì)象列表之后,要顯示這些方法的參數(shù)信息,異常類型和返回值類型等就不難了。這些類型是基本類型還是類類型,都可以由描述類的對(duì)象
18、按順序給出。3.3 獲取類的構(gòu)造器獲取類構(gòu)造器的用法與上述獲取方法的用法類型:Constructor constrctors=c.getDeclaredConstructors();for(Constructor costrctor:constrctors)System.out.println("方法名:"+costrctor.getName();System.out.println("修飾符:"+costrctor.getModifiers();Class params= costrctor.getParameterTypes();for(int i=
19、0;i<params.length;i+)System.out.println("參數(shù)"+paramsi);3.4 獲取類的變量找出一個(gè)類中定義了那些數(shù)字字段也是可能的,下面的代碼就在進(jìn)行這個(gè)事情:Field flelds = c.getDeclaredFields();for(Field fleld:flelds)System.out.println("變量名:"+fleld.getName();System.out.println("修飾符:"+fleld.getModifiers();System.out.println(
20、"返回值類型"+fleld.getType();和獲取方法的情況一樣,獲取字段的時(shí)候也可以只取得在當(dāng)前類中申請(qǐng)了的字段信息(使用getDeclaredFields()方法),或者也可以獲取父類中定義的字段(使用getFields()方法)。4、Java反射應(yīng)用-處理對(duì)象用反射處理對(duì)象的方法*創(chuàng)建新的對(duì)象*執(zhí)行類的方法*修改變量的值*使用數(shù)組4.1 創(chuàng)建類的對(duì)象A、可以根據(jù)構(gòu)造器來實(shí)例化一個(gè)對(duì)象。由于類MyObject的構(gòu)造函數(shù)有兩個(gè)int類型的參數(shù),因此需要先創(chuàng)建一個(gè)類型數(shù)組,在根據(jù)類型數(shù)組獲得構(gòu)造函數(shù):Class paramtypes = new Class2;param
21、types0=int.class;paramtypes1=int.class;Constructor constructor = c.getConstructor(paramtypes);B、然后就可以使用該構(gòu)造函數(shù)constructor來實(shí)例化一個(gè)對(duì)象了。由于該構(gòu)造函數(shù)含有兩個(gè)整形參數(shù),因此需要傳遞倆個(gè)參數(shù)來獲取實(shí)例:Object object = constructor.newInstance(6,3);根據(jù)指定的參數(shù)類型找到相應(yīng)的構(gòu)造函數(shù)并執(zhí)行它,以創(chuàng)建一個(gè)新的對(duì)象實(shí)例。使用這個(gè)方法可以在程序運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建對(duì)象,而不是在編譯的時(shí)候創(chuàng)建對(duì)象,這一點(diǎn)非常有價(jià)值。你也可以使用下面的函數(shù)來調(diào)用
22、午餐的構(gòu)造函數(shù)。/調(diào)用默認(rèn)構(gòu)造函數(shù)Constructor constructor = c.getConstructor();Object object = constructor.newInstance();4.2 改變變量的值Reflection還有一個(gè)用處就是改變對(duì)象數(shù)據(jù)字段的值。Reflection可以從正在運(yùn)行的程序中根據(jù)名稱找到對(duì)象的字段并改變它,下面的例子可以說明這一點(diǎn):Field fielda=c.getField("a");System.out.println("修改前:"+fielda.get(object);fielda.setInt
23、(object, 100);System.out.println("修改后:"+fielda.get(object);4.3 執(zhí)行類的方法到這里,所舉的例子無一例外都與如何獲取類的信息有關(guān)。我們也可以使用Reflection來做一些其他的事情,比如執(zhí)行一個(gè)指定了名稱的方法。如下與構(gòu)造方法的調(diào)用過程相似,需要首先根據(jù)需要調(diào)用方法的參數(shù)類型創(chuàng)建一個(gè)參數(shù)類型數(shù)組,然后再創(chuàng)建一個(gè)輸入值數(shù)組,執(zhí)行方法的調(diào)用。如果函數(shù)沒有參數(shù),直接調(diào)用即可。下面我們分別調(diào)用4個(gè)函數(shù)來執(zhí)行加減乘除的運(yùn)算:/執(zhí)行加法Method method1 = c.getMethod("sum")
24、;Object sum = method1.invoke(object);System.out.println("加="+sum);/執(zhí)行減法Method method2 = c.getMethod("minus");Object minus = method2.invoke(object);System.out.println("減="+minus);/執(zhí)行乘法Method method3 = c.getMethod("multiply");Object multiply = method3.invoke(obj
25、ect);System.out.println("乘="+multiply);/執(zhí)行除法Method method4 = c.getMethod("divide");Object divide = method4.invoke(object);System.out.println("除="+divide);假如一個(gè)程序在執(zhí)行到某處時(shí)才知道需要執(zhí)行某個(gè)方法,這個(gè)方法的名稱是在執(zhí)行程序的運(yùn)行過程中指定的(例如,JavaBean開發(fā)環(huán)境中就會(huì)出現(xiàn)這樣的事情),上面的程序就演示了如何做到。在上例的加法計(jì)算中,getMethod用于查詢一個(gè)具有
26、兩個(gè)整形參數(shù)且名稱為“sum”的方法。找到該方法并創(chuàng)建了相應(yīng)的Method對(duì)象之后,在正確的對(duì)象實(shí)例中執(zhí)行它。執(zhí)行該方法的時(shí)候,需要提供一個(gè)參數(shù)列表,在上例中是分別包裝了整數(shù)9和3的個(gè)int對(duì)象。執(zhí)行方法的返回同樣是一個(gè)Integer對(duì)象4.4 使用數(shù)組本文介紹的Reflection的最后一種用法就是創(chuàng)建的操作數(shù)組。數(shù)組在Java語言中是一種特殊的類型,一個(gè)數(shù)組的引用可以賦值給Object引用。觀察下面的例子看肯數(shù)組時(shí)怎么工作的:/使用數(shù)組Class cls = Class.forName("java.lang.String");Object array = Array.n
27、ewInstance(cls,10);Array.set(array, 5, "String");String str5= (String)Array.get(array,5);System.out.println(str5);例中創(chuàng)建了一個(gè)10個(gè)單位的String數(shù)組,為第5個(gè)位置的字符串賦值,最后將這個(gè)字符串從數(shù)組中獲取并打印出來。下面這段代碼提供了一個(gè)更復(fù)雜的例子:int dims = new int5,10,15;Object arr = Array.newInstance(Integer.Type,dims);Object arrobj = Array.get(a
28、rr,3);Class cls = arrobj.getClass().getComponentType();System.out.println(cls);arrobj=Array.get(arrobj,5);Array.setInt(arrobj,10,37);int arrcast=(int)arr; System.out.println(arrcast3510);例中創(chuàng)建了一個(gè)5X10X15的整形數(shù)組,并為處于3510的元素賦值為37。注意,多維數(shù)組實(shí)際上就是數(shù)組的數(shù)組,例如,第一個(gè)Array.get()之后,arrobj是一個(gè)10X15的數(shù)組。進(jìn)而取得其中的一個(gè)元素,即長(zhǎng)度為15的數(shù)
29、組,并使用Array.setInt()為它的第10個(gè)元素賦值。Java動(dòng)態(tài)代理為了接管目標(biāo)類方法的執(zhí)行,我們應(yīng)該有一種類型鉤子的機(jī)制。例如在windows編程中我們可以利用Hook API來實(shí)現(xiàn)對(duì)某個(gè)Windows API的接管。在Java中同樣也有這樣的一個(gè)機(jī)制,Java提供了java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口,Proxy類主要用來獲取動(dòng)態(tài)代理對(duì)象,InvocationHandler接口用來約束調(diào)用者實(shí)現(xiàn),這兩個(gè)類都在java.lang.reflect包中。本節(jié)我們將首先講解動(dòng)態(tài)代理的機(jī)制,并通過實(shí)際開
30、發(fā)案例講解動(dòng)態(tài)代理的應(yīng)用。最后講解基于動(dòng)態(tài)代理的AOP實(shí)現(xiàn)和字節(jié)碼庫。1 動(dòng)態(tài)代理機(jī)制所謂動(dòng)態(tài)代理,即通過Proxy的代理,接口和實(shí)現(xiàn)類之間可以不直接發(fā)生聯(lián)系,而可以在運(yùn)行期(Runtime)實(shí)現(xiàn)動(dòng)態(tài)關(guān)聯(lián)。Java動(dòng)態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個(gè)類。(1)接口InvocationHandle:該接口中僅定義了一個(gè)方法Object invoke(Object obj,Method method,Object args);在實(shí)際使用時(shí),第一個(gè)參數(shù)obj一般是指代理類,method是被代理的方法,args為該方法的參數(shù)數(shù)組。(2)Proxy:該類即為動(dòng)態(tài)代
31、理類,作用類實(shí)現(xiàn)了InvocationHandler接口的代理類,其中主要包含以下函數(shù)。*protected Proxy(InvocationHandler h):構(gòu)造函數(shù),用于給內(nèi)部的h賦值。*static Class getProxyClass(ClassLoader loader,Class interfaces):獲得一個(gè)代理類,其中l(wèi)oader是類裝載器,interfaces是真實(shí)類所擁有的全部接口的數(shù)組。*static Object newProxyInstance(ClassLoader loader,Class interfaces,InvocationHandler h):返
32、回代理類的一個(gè)實(shí)例,返回后的代理類可以當(dāng)做被代理使用。所謂Dynamic Proxy是這樣一種類:它是在運(yùn)行時(shí)生成的class,在生成它時(shí)你必須提供一組interface給它,然后該class就宣傳自己實(shí)現(xiàn)這些interface。你當(dāng)然可以把該class的實(shí)現(xiàn)當(dāng)做這些interface中的任何一個(gè)來用。當(dāng)然,這個(gè)Dynamic Proxy其實(shí)就是一個(gè)Proxy,它不會(huì)替你做實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)現(xiàn)的工作。2 動(dòng)態(tài)代理應(yīng)用java1.3引用了名為“動(dòng)態(tài)代理類”(Dynamic Proxy Class)的新特性,利用它可為“已知接口的實(shí)現(xiàn)”動(dòng)態(tài)地創(chuàng)建
33、包裝器(wrapper)類。為了更好地演示動(dòng)態(tài)代理的原理,我們從非動(dòng)態(tài)代理的演示開始說起。2.1 定義接口和實(shí)現(xiàn)類并直接調(diào)用為了實(shí)現(xiàn)一系列的不同實(shí)現(xiàn),首先我們定義一個(gè)接口類Hello:public interface Hellovoid say();該接口定義了一個(gè)say()方法,用來約束其實(shí)現(xiàn)函數(shù)來實(shí)現(xiàn)不同的內(nèi)容。接下來我們分別定義兩個(gè)實(shí)現(xiàn)類Hello World和HelloChina,分別執(zhí)行不同的say()代碼:public class HelloWorld implements Hellopublic void say()System.out.println("Hello W
34、orld!");public class HellowChina implements Hellopublic void say()System.out.println("Hello China!");此時(shí),對(duì)應(yīng)這兩個(gè)實(shí)現(xiàn)類,我們可以直接創(chuàng)建它們的實(shí)例,調(diào)用其中的方法:Hello helloWorld = new HelloWorld();Hello chinaWorld = new HelloChina();helloWorld.say();chinaWorld.say();2.2 使用包裝類進(jìn)行包裝假定我們現(xiàn)在想攔截對(duì)HelloWorld或HelloChina
35、類發(fā)出的方法say()的調(diào)用,比如在調(diào)用前和調(diào)用后分別輸出字符串“start to say:”和“end say!”,那么就需要定義一個(gè)對(duì)它們的公共接口類Hello的包裝類HelloWrapper:/包裝類HelloWrapperpublic class HelloWrapper implements Helloprivate Hello wrapped; /包裝對(duì)象public HelloWrapper(Hello hello)this.wrapped = hello;/包裝函數(shù)public void say()System.out.println("start to say&qu
36、ot;);wrapped.say();System.out.println("end say");在該類中包含一個(gè)Hello類的變量wrapped,表示待包裝的實(shí)例對(duì)象,它通過構(gòu)造函數(shù)寫入,并添加了一個(gè)包裝Hello類中say()方法的包裝函數(shù)say(),該函數(shù)在調(diào)用目標(biāo)對(duì)象wrapped的say()函數(shù)的前后分別輸出字符串“start to say:”和“end say!”,這就到達(dá)了包裝的目的。此時(shí)就可以使用該包裝類對(duì)上面的實(shí)例world和china進(jìn)行包裝。分別根據(jù)這兩個(gè)實(shí)例創(chuàng)建兩個(gè)包裝類,然后直接調(diào)用包裝類的方法,即可實(shí)現(xiàn)對(duì)目標(biāo)變量world和china的包裝調(diào)用:
37、HelloWrapper wrapper1 = new HelloWrapper(world);HelloWrapper wrapper2 = new HelloWrapper(china);wrapper1.say();wrapper2.say();對(duì)應(yīng)這種包裝器風(fēng)格的HelloWrapper來說,一旦你想修改Hello接口,它的缺陷就會(huì)暴露出來。為Hello接口添加方法,就得為HelloWrapper類添加一個(gè)包裝器方法。如果我們將HelloWrapper繼承自HelloWorld,即為實(shí)現(xiàn)類HelloWorld實(shí)現(xiàn)包裝器:public class HelloWrapper extends
38、 HelloWorldprivate Hello wrapped; /包裝對(duì)象public HelloWrapper(Hello hello)this.wrapped = hello;/包裝函數(shù)public void say()System.out.println("start to say");wrapped.say();System.out.println("end say");這種方式在修改接口方法時(shí)不必修改包裝器,但是同時(shí)又出現(xiàn)了新的問題,只有HelloWorld對(duì)象才能使用包裝器HelloWrapper。而在此之前,實(shí)現(xiàn)了Hello接口的任何對(duì)
39、象都可以使用HelloWrapper。現(xiàn)在,由Java施加的“線性類出身限制”禁止我們將任意Hello變成一個(gè)HelloWrapper。為此,可以使用動(dòng)態(tài)代理。2.3 使用動(dòng)態(tài)代理動(dòng)態(tài)代理則綜合了以上兩種方案的優(yōu)點(diǎn)。使用動(dòng)態(tài)代理,你創(chuàng)建的包裝器類不要求為所有方法都使用顯式的包裝器。下面的代碼演示了用動(dòng)態(tài)代理來創(chuàng)建一個(gè)代理類HelloHandler,我們創(chuàng)建這個(gè)HelloHandler不需要實(shí)現(xiàn)Hello接口,而是實(shí)現(xiàn)了java.lang.reflect.InvocationHandler,只提供了一個(gè)invoke()方法。代理對(duì)象上的任何方法調(diào)用都要通過這一方法進(jìn)行。觀察invoke()的主體
40、,它包括了被調(diào)用函數(shù)的反射參數(shù)Method,我們可以使用該參數(shù)確定當(dāng)前執(zhí)行方法的屬性。然而,我們得到的仍然只是一個(gè)具有invoke()方法的InvocationHandler,而不是我們真正想要的Hello對(duì)象。動(dòng)態(tài)代理真正的魅力要到創(chuàng)建實(shí)際的Hello實(shí)例時(shí)才能反映出來。它通過調(diào)用HelloHandler的構(gòu)造方法初始化了被包裝的對(duì)象proxyed.InvocationHandler handler1 = new HelloHandler(world);Hello proxy1= (Hello)Proxy.newProxyInstance(world.getClass().getClassL
41、oader(), world.getClass().getInterfaces(), handler1);proxy1.say();InvocationHandler handler2 = new HelloHandler(china);Hello proxy2= (Hello)Proxy.newProxyInstance(world.getClass().getClassLoader(), world.getClass().getInterfaces(), handler2);proxy2.say();這段代碼實(shí)現(xiàn)了world和china的代理調(diào)用。*首先根據(jù)被代理對(duì)象world創(chuàng)建一個(gè)代理
42、類handler1,此處是HelloHandler對(duì)象。*創(chuàng)建動(dòng)態(tài)代理對(duì)象proxy1,它的第一個(gè)參數(shù)為world類的加載器,第二個(gè)參數(shù)為該類的接口,第三個(gè)對(duì)象為代理對(duì)象handler1.*通過動(dòng)態(tài)代理對(duì)象proxy1調(diào)用say()方法,此時(shí)會(huì)在原始對(duì)象HelloWorld.say()方法前后輸入運(yùn)行這段代碼的輸出結(jié)果。上面的代碼表面上很復(fù)雜,但作用很簡(jiǎn)單,就是告訴Proxy類用一個(gè)指定的類加載器來動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象,該對(duì)象要實(shí)現(xiàn)指定的接口(本例為Hello),并用提供的InvocationHandler來代替?zhèn)鹘y(tǒng)的方法主體。結(jié)果對(duì)象在一個(gè)instanceof Hello測(cè)試返回true,提供了
43、在實(shí)現(xiàn)了Hello接口的任何類中都能找到的方法。有趣的是,在HelloHandler類的invoke()方法中,完全不存在對(duì)Hello接口的引用。在本例中我們以一個(gè)構(gòu)造函數(shù)的形式,為HelloHandler提供了Hello的一個(gè)實(shí)例。代理Hello實(shí)例上的任何方法調(diào)用最終都由HelloHandler委托給這個(gè)包裝的Hello.但是,雖然這是最常見的設(shè)計(jì),但你必須了解,InvocationHandler不一定非要委托給被代理的接口的另外一個(gè)實(shí)例。事實(shí)上,InvocationHandler完全能自行提供方法主體,而無須一個(gè)委托目標(biāo)。最后要注意,如果Hello接口中發(fā)生改變,那么Hellohandler中的invoke方法將仍然可以移植,假定say()方法被重命名,那么新的方法名依然會(huì)被攔截。3 基于動(dòng)態(tài)代理的AOP實(shí)現(xiàn)動(dòng)態(tài)代理有一個(gè)很好的用處就是生成調(diào)用st
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 三農(nóng)產(chǎn)品品質(zhì)管理方案
- 數(shù)據(jù)挖掘技術(shù)在業(yè)務(wù)智能化中的應(yīng)用作業(yè)指導(dǎo)書
- 2025年青海貨運(yùn)從業(yè)資格證考試模擬試題及答案大全解析
- 2025年河北貨運(yùn)從業(yè)資格證考試題技巧
- 2025年保山a2貨運(yùn)從業(yè)資格證模擬考試
- 2025年遼寧貨運(yùn)從業(yè)資格證考試資料
- 2025年伊春c1貨運(yùn)上崗證模擬考試
- 2024年高中語文第四單元第13課宇宙的邊疆課時(shí)優(yōu)案1含解析新人教版必修3
- 粵教版道德與法治九年級(jí)上冊(cè)2.1.2《政府社會(huì)治理的主要職責(zé)》聽課評(píng)課記錄
- 初中班主任教師工作計(jì)劃
- 2022年第六屆【普譯獎(jiǎng)】全國(guó)大學(xué)生英語翻譯大賽
- GB/T 14258-2003信息技術(shù)自動(dòng)識(shí)別與數(shù)據(jù)采集技術(shù)條碼符號(hào)印制質(zhì)量的檢驗(yàn)
- 政府資金項(xiàng)目(榮譽(yù))申報(bào)獎(jiǎng)勵(lì)辦法
- JJF 1069-2012 法定計(jì)量檢定機(jī)構(gòu)考核規(guī)范(培訓(xùn)講稿)
- 最新如何進(jìn)行隔代教育專業(yè)知識(shí)講座課件
- 當(dāng)前警察職務(wù)犯罪的特征、原因及防范,司法制度論文
- 計(jì)算機(jī)文化基礎(chǔ)單元設(shè)計(jì)-windows
- 廣東省保安服務(wù)監(jiān)管信息系統(tǒng)用戶手冊(cè)(操作手冊(cè))
- DNA 親子鑒定手冊(cè) 模板
- DB33T 1233-2021 基坑工程地下連續(xù)墻技術(shù)規(guī)程
- 天津 建設(shè)工程委托監(jiān)理合同(示范文本)
評(píng)論
0/150
提交評(píng)論