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、そうでない場合はfalseNullPointerException - clがnullである場合public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
proxy - 呼出しハンドラを返すプロキシ・インスタンスIllegalArgumentException - 引数がプロキシ・インスタンスではない場合SecurityException - セキュリティ・マネージャsが存在し、呼出し側のクラス・ローダーが呼出しハンドラのクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()の呼出しが呼出しハンドラのクラスのアクセスを許可しない。 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。 そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2025, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Documentation Redistribution Policyも参照してください。