public class Proxy extends Object implements Serializable
Proxy
は、動的プロキシのクラスおよびインスタンスを作成するstaticメソッドを提供し、また、それらのメソッドによって作成された動的プロキシ・クラスすべてのスーパー・クラスでもあります。
インタフェースFoo
のプロキシを生成するには、次のように設定します。
InvocationHandler handler = new MyInvocationHandler(...); Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class); Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class). newInstance(handler);あるいはもっと単純に、次のように設定します。
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
動的プロキシ・クラス (以下単にプロキシ・クラスと呼ぶ)は、クラス生成の実行時に指定されたインタフェースのリストを実装するクラスで、以下に述べる動作をします。プロキシ・インタフェースは、プロキシ・クラスが実装するインタフェースです。プロキシ・インスタンスは、プロキシ・クラスのインスタンスです。各プロキシ・インスタンスには関連付けられた呼出しハンドラオブジェクトがあり、それにはインタフェースInvocationHandler
が実装されています。プロキシ・インタフェースの1つを使ったプロキシ・インスタンスでのメソッド呼出しは、インスタンスの呼出しハンドラの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.ProtectionDomainと同じです。プロキシ・クラスのコードは、信頼されたシステム・コードによって生成されるためです。標準では、この保護ドメインに対してjava.security.AllPermission
が与えられます。
InvocationHandler
の実装を取る1つのpublicコンストラクタがあります。プロキシ・インスタンスは、リフレクションAPIを介してpublicコンストラクタにアクセスしなくても、Proxy.newProxyInstance
メソッドを呼び出すことによっても作成できます。このメソッドでは、Proxy.getProxyClass
を呼び出すアクションと、呼出しハンドラを使用してコンストラクタを呼び出すアクションが行われます。
プロキシ・インスタンスには以下のプロパティがあります。
Foo
がプロキシ・インスタンスproxy
およびインタフェースの1つを実装している場合、次の式が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
から継承されるプロキシ・インスタンスのその他のpublicメソッドは、プロキシ・クラスによってオーバーライドされません。このため、これらのメソッドの呼出しは、java.lang.Object
のインスタンスに対する呼び出しと同様に行われます。
複数のインタフェースに、同じ名前とパラメータ・シグネチャを持つメソッドが含まれる場合は、プロキシ・クラスのインタフェースの順番が区別されます。プロキシ・インスタンス上で重複するメソッドが呼び出された場合、呼出しハンドラに渡されるMethod
オブジェクトで、プロキシ・メソッドの呼出しに使用されたインタフェースの参照型から宣言クラスを割り当てることができないことがあります。このような制約が存在するのは、生成されたプロキシ・クラス内の対応するメソッドの実装から、その実装が呼び出されたときに使用されたインタフェースを特定できないためです。このため、プロキシ・インスタンス上で重複するメソッドが呼び出された場合は、メソッド呼出しに使用された参照型にかかわりなく、プロキシ・クラスのインタフェース・リストでそのメソッド(直接またはスーパー・インタフェースから継承)を含むインタフェースのうち、最初のインタフェースのメソッドのMethod
オブジェクトが呼出しハンドラのinvoke
メソッドに渡されます。
プロキシ・インタフェースに、java.lang.Object
のhashCode
、equals
、またはtoString
メソッドと同じ名前およびパラメータ・シグネチャを持つメソッドが含まれる場合は、プロキシ・インスタンス上でそのメソッドが呼び出されると、呼出しハンドラに渡されるMethod
オブジェクトの宣言クラスはjava.lang.Object
になります。つまり、publicで非finalであるjava.lang.Object
のメソッドは、呼出しハンドラに渡すMethod
オブジェクトを決定するときに、論理的にほかのプロキシ・インタフェースより優先されます。
重複するメソッドが呼出しハンドラにディスパッチされた場合は、invoke
メソッドからスローできるチェック例外の型は、チェックされる型のうち、呼び出されるすべてのプロキシ・インタフェースのメソッドに指定されている、throws
句の例外の型に割り当てることができるものに限定されます。invoke
メソッドが、呼出しに使えるプロキシ・インタフェースの1つのメソッドで宣言された例外タイプのどれにも割当てできないチェック例外をスローした場合、チェックされないUndeclaredThrowableException
がプロキシ・インスタンスでの呼出しによってスローされます。つまり、invoke
メソッドに渡されたMethod
オブジェクト上で、getExceptionTypes
を呼び出して例外の型を取得しても、invoke
メソッドから正常にスローされないことがあります。
InvocationHandler
, 直列化された形式修飾子と型 | フィールドと説明 |
---|---|
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)
指定された呼出しハンドラに対してメソッド呼出しをディスパッチする、指定されたインタフェースのプロキシ・クラスのインスタンスを返します。
|
protected InvocationHandler h
protected Proxy(InvocationHandler h)
Proxy
インスタンスを構築します。h
- このプロキシ・インスタンスの呼出しハンドラNullPointerException
- 指定された呼び出しハンドラh
がnull
の場合public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
java.lang.Class
オブジェクトを返します。プロキシ・クラスは指定されたクラス・ローダーにより定義され、指定されたインタフェースをすべて実装します。指定されたインタフェースのいずれかが非publicである場合、プロキシ・クラスは非publicになります。インタフェースの同じ順列のプロキシ・クラスがすでにクラス・ローダーにより定義されている場合、既存のプロキシ・クラスが返されます。そうでない場合は、これらのインタフェースのプロキシ・クラスが動的に生成され、クラス・ローダーにより定義されます。
Proxy.getProxyClass
に引き渡されるパラメータには、いくつかの制約があります。
interfaces
配列のClass
オブジェクトはすべて、クラスまたはプリミティブ型ではなくインタフェースを表す必要がある。
interfaces
配列の2つの要素が同一のClass
オブジェクトを参照することはできない。
cl
、各インタフェースがi
の場合は、次の式がtrueでなければならない。
Class.forName(i.getName(), false, cl) == i
interfaces
配列のサイズは65535を超えてはならない。
これらの制約に対して違反が発生した場合は、Proxy.getProxyClass
によってIllegalArgumentException
がスローされます。interfaces
配列引数またはそのいずれかの要素がnull
の場合、NullPointerException
がスローされます。
プロキシ・インタフェースは、順番が区別されます。プロキシ・クラスを2回要求したときに、インタフェースの組み合わせが同じで順番が異なる場合は、2つの異なるプロキシ・クラスが作成されます。
loader
- プロキシ・クラスを定義するクラス・ローダーinterfaces
- プロキシ・クラスが実装するインタフェースのリストIllegalArgumentException
- getProxyClass
に引き渡されるパラメータに関する制約のどれかが守られなかった場合SecurityException
- セキュリティ・マネージャsが存在し、次の条件のどれかが満たされる場合:
loader
がnull
で、呼出し側のクラス・ローダーがnull
ではなく、RuntimePermission("getClassLoader")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。intf
について、呼出し側のクラス・ローダーがintf
のクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しがintf
へのアクセスを許可しない。NullPointerException
- interfaces
配列の引数またはその要素のいずれかがnull
の場合public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Proxy.getProxyClass
の場合と同じ理由で、Proxy.newProxyInstance
はIllegalArgumentException
をスローします。
loader
- プロキシ・クラスを定義するクラス・ローダーinterfaces
- プロキシ・クラスが実装するインタフェースのリストh
- メソッド呼出しのディスパッチ先の呼出しハンドラIllegalArgumentException
- getProxyClass
に引き渡されるパラメータに関する制約のどれかが守られなかった場合SecurityException
- セキュリティ・マネージャsが存在し、次の条件のどれかが満たされる場合:
loader
がnull
で、呼出し側のクラス・ローダーがnull
ではなく、RuntimePermission("getClassLoader")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。intf
について、呼出し側のクラス・ローダーがintf
のクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しがintf
へのアクセスを許可しない。ReflectPermission("newProxyInPackage.{package name}")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。NullPointerException
- interfaces
配列の引数またはその要素のいずれかがnull
の場合、または呼出しハンドラh
がnull
の場合public static boolean isProxyClass(Class<?> cl)
getProxyClass
メソッドまたはnewProxyInstance
メソッドを使って動的に生成されてプロキシ・クラスとなる場合にだけ、trueを返します。
セキュリティを判定するときにこのメソッドを使用する場合は、信頼性が重要になります。このため、渡されたクラスがProxy
を継承しているかどうかを検査してから、追加の検査を行う必要があります。
cl
- テストするクラスtrue
、そうでない場合はfalse
NullPointerException
- cl
がnull
である場合public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
proxy
- 呼出しハンドラを返すプロキシ・インスタンスIllegalArgumentException
- 引数がプロキシ・インスタンスではない場合SecurityException
- セキュリティ・マネージャsが存在し、呼出し側のクラス・ローダーが呼出しハンドラのクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しが呼出しハンドラのクラスのアクセスを許可しない。 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.