Java程序员从笨鸟到菜鸟之(八)反射和代理机制
反射和代理機(jī)制是JDK5.0提供的Java新特性,反射的出現(xiàn)打破了java一些常規(guī)的規(guī)則,如,私有變量不可訪問。但反射和代理在學(xué)習(xí)過程中也是一個(gè)比較難理解的知識(shí)點(diǎn)。本人曾經(jīng)學(xué)過一段時(shí)間的反射和代理,但好長(zhǎng)時(shí)間不用好像有點(diǎn)生疏了,當(dāng)時(shí)學(xué)的時(shí)候就理解的不是很透徹,這次總結(jié)算是重新學(xué)習(xí)一遍吧,如果有什么錯(cuò)誤,請(qǐng)大家拍磚:
?先看一下,Java?反射機(jī)制主要提供了以下功能:
?在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。
?在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象。
?在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法。
?在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法
?????一般而言,開發(fā)者社群說到動(dòng)態(tài)語言,大致認(rèn)同的一個(gè)定義是:“程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言”盡管在這樣的定義與分類下Java不是動(dòng)態(tài)語言,它卻有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制:Reflection。這個(gè)字的意思是“反射、映象、倒影”,用在Java身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對(duì)象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods。這種“看透class”的能力(the?ability?of?the?program?to?examine?itself)被稱為introspection(內(nèi)省、內(nèi)觀、反省)。Reflection和introspection是常被并提的兩個(gè)術(shù)語
API簡(jiǎn)介
?????在JDK中,主要由以下類來實(shí)現(xiàn)Java反射機(jī)制,這些類都位于java.lang.reflect包中
–Class類:代表一個(gè)類。
–Field?類:代表類的成員變量(成員變量也稱為類的屬性)。
–Method類:代表類的方法。
–Constructor?類:代表類的構(gòu)造方法。
–Array類:提供了動(dòng)態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組的元素的靜態(tài)方法
???????在java.lang.Object類中定義了getClass()方法,因此對(duì)于任意一個(gè)Java對(duì)象,都可以通過此方法獲得對(duì)象的類型。
Class類是Reflection?API?中的核心類,它有以下方法
–getName():獲得類的完整名字。
–getFields():獲得類的public類型的屬性。
–getDeclaredFields():獲得類的所有屬性。
–getMethods():獲得類的public類型的方法。
–getDeclaredMethods():獲得類的所有方法。
-getMethod(String?name,?Class[]?parameterTypes):獲得類的特定方法,name參數(shù)指定方法的名字,parameterTypes參數(shù)指定方法的參數(shù)類型。
-getConstructors():獲得類的public類型的構(gòu)造方法。
?getConstructor(Class[]?parameterTypes):獲得類的特定構(gòu)造方法,parameterTypes參數(shù)指定構(gòu)造方法的參數(shù)類型。
?newInstance():通過類的不帶參數(shù)的構(gòu)造方法創(chuàng)建這個(gè)類的一個(gè)對(duì)象。
?(2)通過默認(rèn)構(gòu)造方法創(chuàng)建一個(gè)新對(duì)象:
?Object?objectCopy=classType.getConstructor(new?Class[]{}).newInstance(new?Object[]{});
?以上代碼先調(diào)用Class類的getConstructor()方法獲得一個(gè)Constructor?對(duì)象,它代表默認(rèn)的構(gòu)造方法,然后調(diào)用Constructor對(duì)象的newInstance()方法構(gòu)造一個(gè)實(shí)例。
?(3)獲得對(duì)象的所有屬性:
?Field?fields[]=classType.getDeclaredFields();
?Class?類的getDeclaredFields()方法返回類的所有屬性,包括public、protected、默認(rèn)和private訪問級(jí)別的屬性
(4)Method類的invoke(Object?obj,Object?args[])方法接收的參數(shù)必須為對(duì)象,如果參數(shù)為基本類型數(shù)據(jù),必須轉(zhuǎn)換為相應(yīng)的包裝類型的對(duì)象。invoke()方法的返回值總是對(duì)象,如果實(shí)際被調(diào)用的方法的返回類型是基本類型數(shù)據(jù),那么invoke()方法會(huì)把它轉(zhuǎn)換為相應(yīng)的包裝類型的對(duì)象,再將其返回
(5)Java中,無論生成某個(gè)類的多少個(gè)對(duì)象,這些對(duì)象都會(huì)對(duì)應(yīng)于同一個(gè)Class對(duì)象。?要想使用反射,首先需要獲得待處理類或?qū)ο笏鶎?duì)應(yīng)的Class對(duì)象。?
獲取某個(gè)類或某個(gè)對(duì)象所對(duì)應(yīng)的Class對(duì)象的常用的3種方式:?
a)?使用Class類的靜態(tài)方法forName:Class.forName(“java.lang.String”);?
b)?使用類的.class語法:String.class;?
c)?使用對(duì)象的getClass()方法:String?s?=?“aa”;?Class<?>?clazz?=?s.getClass();?
下面寫一個(gè)程序來用一下這些API吧:
[java]?view plaincopy print?
注:1)處的int.class,int.class可以寫為new?Class[]{int.class,int.class}
原因在于getMethod方法的第二個(gè)參數(shù)是一個(gè)可變參數(shù)。
2)處的1,2可以寫為new?int【】{1,2},原因如1);
4.若想通過類的不帶參數(shù)的構(gòu)造方法來生成對(duì)象,我們有兩種方式:?
a)?先獲得Class對(duì)象,然后通過該Class對(duì)象的newInstance()方法直接生成即可:?
Class<?>?classType?=?String.class;?
Object?obj?=?classType.newInstance();?
b)?先獲得Class對(duì)象,然后通過該對(duì)象獲得對(duì)應(yīng)的Constructor對(duì)象,再通過該Constructor對(duì)象的newInstance()方法生成:?
Class<?>?classType?=?Customer.class;?
Constructor?cons?=?classType.getConstructor(new?Class[]{});?
Object?obj?=?cons.newInstance(new?Object[]{});?
注:
4.?若想通過類的帶參數(shù)的構(gòu)造方法生成對(duì)象,只能使用下面這一種方式:?
Class<?>?classType?=?Customer.class;?
Constructor?cons?=?classType.getConstructor(new?Class[]{String.class,?int.class});?
Object?obj?=?cons.newInstance(new?Object[]{“hello”,?3});?
?代碼示例:
[java]?view plaincopy print?
5.Integer.TYPE返回的是int,而Integer.class返回的是Integer類所對(duì)應(yīng)的Class對(duì)象。?
java.lang.Array?類提供了動(dòng)態(tài)創(chuàng)建和訪問數(shù)組元素的各種靜態(tài)方法
一維數(shù)組的簡(jiǎn)單創(chuàng)建,設(shè)值,取值
Object?array?=?Array.newInstance(classType,?10);
Array.set(array,?5,?"hello");
String?str?=?(String)Array.get(array,?5);
二維數(shù)組的簡(jiǎn)單創(chuàng)建,設(shè)值,取值
[java]?view plaincopy print?
利用反射訪問類的私有方法:
代碼示例:
[java]?view plaincopy print?
利用反射訪問類的私有變量:
[java]?view plaincopy print?
???????????????????????????????????????????????????????????????????????????????代理
代理模式的作用是:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。
?在某些情況下,一個(gè)客戶不想或者不能直接引用另一個(gè)對(duì)象,而代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到中介的作用
代理模式一般涉及到的角色有
–抽象角色:聲明真實(shí)對(duì)象和代理對(duì)象的共同接口
–代理角色:代理對(duì)象角色內(nèi)部含有對(duì)真實(shí)對(duì)象的引用,從而可以操作真實(shí)對(duì)象,同時(shí)代理對(duì)象提供與真實(shí)對(duì)象相同的接口以便在任何時(shí)刻都能代替真實(shí)對(duì)象。同時(shí),代理對(duì)象可以在執(zhí)行真實(shí)對(duì)象操作時(shí),附加其他的操作,相當(dāng)于對(duì)真實(shí)對(duì)象進(jìn)行封裝
–真實(shí)角色:代理角色所代表的真實(shí)對(duì)象,是我們最終要引用的對(duì)象
Java動(dòng)態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個(gè)類:
?(1)Interface?InvocationHandler:該接口中僅定義了一個(gè)方法
–public?object?invoke(Object?obj,Method?method,?Object[]?args)
?在實(shí)際使用時(shí),第一個(gè)參數(shù)obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數(shù)數(shù)組。這個(gè)抽象方法在代理類中動(dòng)態(tài)實(shí)現(xiàn)。
?(2)Proxy:該類即為動(dòng)態(tài)代理類,作用類似于上例中的ProxySubject,其中主要包含以下內(nèi)容
?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):返回代理類的一個(gè)實(shí)例,返回后的代理類可以當(dāng)作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)
所謂Dynamic?Proxy(動(dòng)態(tài)代理)是這樣一種class:它是在運(yùn)行時(shí)生成的class,在生成它時(shí)你必須提供一組interface給它,然后該class就宣稱它實(shí)現(xiàn)了這些interface。你當(dāng)然可以把該class的實(shí)例當(dāng)作這些interface中的任何一個(gè)來用。當(dāng)然,這個(gè)Dynamic?Proxy其實(shí)就是一個(gè)Proxy,它不會(huì)替你作實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工作
在使用動(dòng)態(tài)代理類時(shí),我們必須實(shí)現(xiàn)InvocationHandler接口
通過代理的方式,被代理的對(duì)象(RealSubject)可以在運(yùn)行時(shí)動(dòng)態(tài)改變,需要控制的接口(Subject接口)可以在運(yùn)行時(shí)改變,控制的方式(DynamicSubject類)也可以動(dòng)態(tài)改變,從而實(shí)現(xiàn)了非常靈活的動(dòng)態(tài)代理關(guān)系
動(dòng)態(tài)代理是指客戶通過代理類來調(diào)用其它對(duì)象的方法
?動(dòng)態(tài)代理使用場(chǎng)合:
????調(diào)試
????遠(yuǎn)程方法調(diào)用(RMI)
動(dòng)態(tài)代理的步驟:
1.創(chuàng)建一個(gè)實(shí)現(xiàn)接口InvocationHandler的類,它必須實(shí)現(xiàn)invoke方法
2.創(chuàng)建被代理的類以及接口
3.通過Proxy的靜態(tài)方法
newProxyInstance(ClassLoader?loader,?Class[]?interfaces,?InvocationHandler?h)?創(chuàng)建一個(gè)代理
4.通過代理調(diào)用方法
?本文來自:曹勝歡博客專欄。轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.Net/csh624366188
總結(jié)
以上是生活随笔為你收集整理的Java程序员从笨鸟到菜鸟之(八)反射和代理机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java程序员从笨鸟到菜鸟之(七)一—j
- 下一篇: Java程序员从笨鸟到菜鸟之(九)——数