java.lang.reflect
類 Proxy
java.lang.Object
-java.lang.reflect.Proxy
所有已實現的接口:
public class Proxy
extends Objectimplements Serializable
Proxy
提供用於創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。
創建某一接口 Foo
的代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
或使用以下更簡單的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
動態代理類(以下簡稱爲代理類)是一個實現在創建類時在運行時指定的接口列表的類,該類具有下面描述的行爲。 代理接口 是代理類實現的一個接口。 代理實例 是代理類的一個實例。 每個代理實例都有一個關聯的調用處理程序 對象,它可以實現接口 InvocationHandler
。通過其中一個代理接口的代理實例上的方法調用將被指派到實例的調用處理程序的 Invoke
方法,並傳遞代理實例、識別調用方法的 java.lang.reflect.Method
對象以及包含參數的 Object
類型的數組。調用處理程序以適當的方式處理編碼的方法調用,並且它返回的結果將作爲代理實例上方法調用的結果返回。
代理類具用以下屬性:
- 代理類是公共的、最終的,而不是抽象的。
- 未指定代理類的非限定名稱。但是,以字符串
"$Proxy"
開頭的類名空間應該爲代理類保留。 - 代理類擴展
java.lang.reflect.Proxy
。 - 代理類會按同一順序準確地實現其創建時指定的接口。
- 如果代理類實現了非公共接口,那麼它將在與該接口相同的包中定義。否則,代理類的包也是未指定的。注意,包密封將不阻止代理類在運行時在特定包中的成功定義,也不會阻止相同類加載器和帶有特定簽名的包所定義的類。
- 由於代理類將實現所有在其創建時指定的接口,所以對其
Class
對象調用getInterfaces
將返回一個包含相同接口列表的數組(按其創建時指定的順序),對其Class
對象調用getMethods
將返回一個包括這些接口中所有方法的Method
對象的數組,並且調用getMethod
將會在代理接口中找到期望的一些方法。 - 如果
Proxy.isProxyClass
方法傳遞代理類(由Proxy.getProxyClass
返回的類,或由Proxy.newProxyInstance
返回的對象的類),則該方法返回 true,否則返回 false。 - 代理類的
java.security.ProtectionDomain
與由引導類加載器(如java.lang.Object
)加載的系統類相同,原因是代理類的代碼由受信任的系統代碼生成。此保護域通常被授予java.security.AllPermission
。 - 每個代理類都有一個可以帶一個參數(接口
InvocationHandler
的實現)的公共構造方法,用於設置代理實例的調用處理程序。並非必須使用反射 API 才能訪問公共構造方法,通過調用Proxy.newInstance
方法(將調用Proxy.getProxyClass
的操作和調用帶有調用處理程序的構造方法結合在一起)也可以創建代理實例。
代理實例具有以下屬性:
- 提供代理實例
proxy
和一個由其代理類Foo
實現的接口,以下表達式將返回 true:proxy instanceof Foo
ClassCastException
):(Foo) proxy
- 每個代理實例都有一個關聯的調用處理程序,它會被傳遞到其構造方法中。靜態
Proxy.getInvocationHandler
方法將返回與作爲其參數傳遞的代理實例相關的調用處理程序。 - 代理實例上的接口方法調用將按照該方法的文檔描述進行編碼,並被指派到調用處理程序的
Invoke
方法。 - 在代理實例上的
java.lang.Object
中聲明的hashCode
、equals
或toString
方法的調用將按照與編碼和指派接口方法調用相同的方式進行編碼,並被指派到調用處理程序的invoke
方法,如上所述。傳遞到invoke
的Method
對象的聲明類是java.lang.Object
。代理類不重寫從java.lang.Object
繼承的代理實例的其他公共方法,所以這些方法的調用行爲與其對java.lang.Object
實例的操作一樣。
在多代理接口中重複的方法
當代理類的兩個或多個接口包含一個具有相同名稱和參數簽名的方法時,代理類的接口順序變得非常重要。在代理實例上調用重複方法 時,傳遞到調用處理程序的 Method
對象沒有必要成爲其聲明類可以從接口(通過該接口調用代理方法)的引用類型指派的對象。此限制存在的原因是,生成的代理類中的相應方法實現無法確定它通過哪一個接口調用。因此,在代理實例上調用重複方法時,第一個接口中的方法的 Method
對象包含接口的代理類列表中的方法(直接或通過超級接口繼承),該對象會傳遞到調用處理程序的 invoke
方法,無論該方法調用通過哪一種引用類型發生。
如果代理接口包含某一方法,它的名稱和參數簽名與 java.lang.Object
的 hashCode
、equals
或 toString
方法相同,那麼在代理實例上調用這樣的方法時,傳遞到調用處理程序的 Method
對象將使 java.lang.Object
成爲其聲明類。換句話說,java.lang.Object
公共的非最終方法理論上在所有代理接口之前,以便確定哪一個 Method
對象傳遞到調用處理程序。
還要注意,當重複方法被指派到調用處理程序時,invoke
方法只可以拋出經過檢查的異常類型,該異常類型可以使用所有 代理接口(可以通過它調用)中方法的 throws
子句指派一種異常類型。如果 invoke
方法拋出一個經過檢查的異常,該異常沒有指派給任何由一個代理接口(可以通過它調用)中的方法聲明的異常類型,那麼該代理實例上的調用將拋出一個未經檢查的 UndeclaredThrowableException
。此限制表示並非所有的由傳遞到 invoke
方法的 Method
對象上調用 getExceptionTypes
返回的異常類型都可以由 invoke
方法成功拋出。
從以下版本開始:
1.3
另請參見:
字段摘要 | |
---|---|
protected InvocationHandler |
h 此代理實例的調用處理程序。 |
構造方法摘要 | |
---|---|
protected |
Proxy(InvocationHandler h) 使用其調用處理程序的指定值從子類(通常爲動態代理類)構建新的 Proxy 實例。 |
方法摘要 | |
---|---|
static InvocationHandler |
getInvocationHandler(Object proxy) 返回指定代理實例的調用處理程序。 |
static Class<?> |
getProxyClass(ClassLoader loader, Class<?>... interfaces) 返回代理類的 java.lang.Class 對象,並向其提供類加載器和接口數組。 |
static boolean |
isProxyClass(Class<?> cl) 當且僅當指定的類通過 getProxyClass 方法或 newProxyInstance 方法動態生成爲代理類時,返回 true。 |
static Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。 |
從類 java.lang.Object 繼承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
字段詳細信息 |
---|
h
protected InvocationHandler h
此代理實例的調用處理程序。
構造方法詳細信息 |
---|
Proxy
protected Proxy(InvocationHandler h)
使用其調用處理程序的指定值從子類(通常爲動態代理類)構建新的 Proxy
實例。
參數:
h
- 此代理實例的調用處理程序
方法詳細信息 |
---|
getProxyClass
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
返回代理類的 java.lang.Class
對象,並向其提供類加載器和接口數組。該代理類將由指定的類加載器定義,並將實現提供的所有接口。如果類加載器已經定義了具有相同排列接口的代理類,那麼現有的代理類將被返回;否則,類加載器將動態生成並定義這些接口的代理類。
對可以傳遞給 Proxy.getProxyClass
的參數有以下幾個限制:
interfaces
數組中的所有Class
對象必須表示接口,而不能表示類或基本類型。interfaces
數組中的兩個元素不能引用同一Class
對象。- 所有接口類型的名稱通過特定的類加載器必須可見。換句話說,對於類加載器
cl
和所有接口i
,以下表達式必須爲 true:Class.forName(i.getName(), false, cl) == i
- 所有非公共接口必須位於同一包中;否則,該代理類將不可能實現所有的接口,無論它在哪一個包中定義。
- 對於有相同簽名的指定接口中任何成員方法集:
- 如果任何方法的返回類型是基本類型或 void,那麼所有的方法必須具有與此相同的返回類型。
- 否則,該方法之一必須是返回類型,它可以指派給該方法其餘的所有返回類型。
- 得到的代理類必須不超過虛擬機在類上施加的任何限制。例如,虛擬機可以限制某一類實現至多 65535 的接口數;在這種情況下,
interfaces
數組的大小必須不超過 65535。
如果違反了這些限制,Proxy.getProxyClass
將拋出 IllegalArgumentException
。如果 interfaces
數組參數或其任何元素爲 null
,則將拋出 NullPointerException
。
注意,指定的代理接口的順序非常重要:對接口組合相同但順序不同的代理類的兩個請求會導致兩個不同的代理類。
參數:
loader
- 定義代理類的類加載器
interfaces
- 代理類要實現的接口列表
返回:
用指定的類加載器定義的代理類,它可以實現指定的接口
拋出:
IllegalArgumentException
- 如果違反傳遞到 getProxyClass
的參數上的任何限制
NullPointerException
- 如果 interfaces
數組參數或其任何元素爲 null
newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。此方法相當於:
Proxy.getProxyClass(loader, interfaces).
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
Proxy.newProxyInstance
拋出 IllegalArgumentException
,原因與 Proxy.getProxyClass
相同。
參數:
loader
- 定義代理類的類加載器
interfaces
- 代理類要實現的接口列表
h
- 指派方法調用的調用處理程序
返回:
一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,並實現指定的接口
拋出:
IllegalArgumentException
- 如果違反傳遞到 getProxyClass
的參數上的任何限制
NullPointerException
- 如果 interfaces
數組參數或其任何元素爲 null
,或如果調用處理程序 h
爲 null
isProxyClass
public static boolean isProxyClass(Class<?> cl)
當且僅當指定的類通過 getProxyClass
方法或 newProxyInstance
方法動態生成爲代理類時,返回 true。
此方法的可靠性對於使用它做出安全決策而言非常重要,所以此方法的實現不應僅測試相關的類是否可以擴展 Proxy
。
參數:
cl
- 要測試的類
返回:
如該類爲代理類,則爲 true
,否則爲 false
拋出:
NullPointerException
- 如果 cl
爲 null
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
返回指定代理實例的調用處理程序。
參數:
proxy
- 返回調用處理程序的代理實例
返回:
代理實例的調用處理程序
拋出:
IllegalArgumentException
- 如果參數不是一個代理實例