- java.lang.Object
-
- java.lang.reflect.Proxy
-
- すべての実装されたインタフェース:
Serializable
public class Proxy extends Object implements Serializable
Proxy
は、インタフェースのインスタンスのように動作するが、カスタマイズされたメソッド呼び出しを可能にするオブジェクトを作成する静的メソッドを提供します。 インタフェースFoo
のプロキシ・インスタンスを作成するには:InvocationHandler handler = new MyInvocationHandler(...); Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
「プロキシ・クラス」は、実行時に作成され、「プロキシ・インタフェース」と呼ばれる指定されたインタフェースのリストを実装するクラスです。 プロキシ・インスタンスは、プロキシ・クラスのインスタンスです。 各プロキシ・インスタンスには関連付けられた呼出しハンドラ・オブジェクトがあり、それにはインタフェース
InvocationHandler
が実装されています。 プロキシ・インタフェースの1つを使ったプロキシ・インスタンスでのメソッド呼出しは、インスタンスの呼出しハンドラのinvoke
メソッドにディスパッチされ、呼び出されたメソッドを識別するjava.lang.reflect.Method
オブジェクト、および引数を格納するObject
型の配列をプロキシ・インスタンスに引き渡します。 呼出しハンドラは符号化されたメソッド呼出しを適切に処理し、呼出しハンドラが返す結果が、プロキシ・インスタンスでのメソッド呼出しの結果として返されます。プロキシ・クラスには次のプロパティがあります。
- プロキシ・クラスの修飾されていない名前は指定されません。 ただし文字列「
$Proxy
」で始まるクラス名の領域をプロキシ・クラスのために確保しておく必要があります。 - プロキシ・クラスが定義されているパッケージおよびモジュールは、belowで指定します。
- プロキシ・クラスは「最終的かつ非抽象的」です。
- プロキシ・クラスは
java.lang.reflect.Proxy
を継承します。 - プロキシ・クラスはその生成時に指定されたとおりのインタフェースを、同じ順序で実装します。 その
Class
オブジェクト上getMethods
呼び出し、インタフェース(その作成時に指定された順序で)の同じリストを含む配列が返され、そのClass
オブジェクト上getInterfaces
呼び出すと、それらのインタフェースのメソッドのすべてを含むMethod
オブジェクトの配列を返し、getMethod
を起動すると、プロキシのメソッドを見つけますインタフェースが期待されるようになります。 - プロキシ・クラスの
ProtectionDomain
は、信頼できるシステム・コードによってプロキシ・クラスのコードが生成されるため、ブートストラップ・クラス・ローダーによってロードされるシステム・クラスのProtectionDomain
(java.lang.Object
など)と同じです。 標準では、この保護ドメインに対してjava.security.AllPermission
が与えられます。 Proxy.isProxyClass
メソッドを使用して、指定されたクラスがプロキシ・クラスであるかどうかを判断できます。
プロキシ・インスタンスには次のプロパティがあります。
- プロキシ・インスタンス
proxy
と、プロキシ・クラスによって実装されたインタフェースFoo
の1つが指定されている場合、次の式はtrueを返します:proxy instanceof Foo
ClassCastException
をスローする場合を除く)。(Foo) proxy
- 各プロキシ・インスタンスには、そのコンストラクタに引き渡された、関連する呼出しハンドラがあります。 static
Proxy.getInvocationHandler
メソッドは、その引数として渡されたプロキシ・インスタンスに関連付けられた呼出しハンドラを返します。 - プロキシ・インスタンスでのインタフェース・メソッドの呼出しは、そのメソッドのドキュメントで述べられているように符号化され、呼出しハンドラの
invoke
メソッドにディスパッチされます。 - プロキシ・インスタンス上の
java.lang.Object
に宣言されているhashCode
、equals
またはtoString
の呼出しは、前述したようにインタフェース・メソッド呼出しと同じ方法で、エンコードされ、呼出しハンドラのinvoke
メソッドにディスパッチされます。invoke
に渡されるMethod
オブジェクトの宣言クラスは、java.lang.Object
です。java.lang.Object
から継承されるプロキシ・インスタンスのその他のpublicメソッドは、プロキシ・クラスによってオーバーライドされません。このため、これらのメソッドの呼出しは、java.lang.Object
のインスタンスに対する呼出しと同様に行われます。
プロキシ・クラスのパッケージとモジュールのメンバーシップ
プロキシ・クラスが属するパッケージおよびモジュールは、プロキシ・クラスのアクセシビリティがプロキシ・インタフェースのアクセシビリティと一致するように選択されます。 具体的には、getProxyClass(ClassLoader, Class[])
またはnewProxyInstance(ClassLoader, Class[], InvocationHandler)
メソッドで定義されたプロキシ・クラスのパッケージおよびモジュール・メンバーシップは、次のように指定されます:- すべてのプロキシ・インタフェースがexportedまたはopenパッケージにある場合は、次のようになります:
- すべてのプロキシ・インタフェースがpublicの場合、プロキシ・クラスは、指定されたローダーの「名前のないモジュール」によってエクスポートされたパッケージ内のpublicです。 パッケージ名は不定です。
- すべてのプロキシ・インタフェースの少なくとも1つがnon-publicである場合、プロキシ・クラスは非パブリック・インタフェースのパッケージおよびモジュール内のnon-publicです。 すべての非公開インタフェースは、同じパッケージとモジュールになければなりません。それ以外の場合、プロキシは「ありえない」です。
- non-exportedおよびnon-openであるパッケージに少なくとも1つのプロキシ・インタフェースがある場合:
- すべてのプロキシ・インタフェースがpublicの場合、「動的モジュール。」のnon-exported、non-openパッケージのプロキシ・クラスはpublicです パッケージとモジュールの名前が指定されていません。
- すべてのプロキシ・インタフェースの少なくとも1つがnon-publicである場合、プロキシ・クラスは非パブリック・インタフェースのパッケージおよびモジュール内のnon-publicです。 すべての非公開インタフェースは、同じパッケージとモジュールになければなりません。それ以外の場合、プロキシは「ありえない」です。
プロキシ・インタフェースが複数の機能を備えている場合-- たとえば、エクスポートされたパブリック・インタフェースとエクスポートされていない非パブリック・インタフェース-- 同じインスタンスによってプロキシされる場合、プロキシ・クラスのアクセシビリティは、最もアクセスしにくいプロキシ・インタフェースによって管理されます。
任意のコードが
setAccessible
を使用してオープン・パッケージ内のプロキシ・クラスにアクセスすることは可能ですが、非オープン・パッケージ内のプロキシ・クラスはプロキシ・クラスのモジュール外でコードにアクセスすることはできません。この仕様では、"エクスポートされていないパッケージ"はすべてのモジュールにエクスポートされていないパッケージを指し、"非オープン・パッケージ"はすべてのモジュールに対して開かれていないパッケージを指します。 具体的には、これらの用語は、その包含モジュールによってエクスポート/オープンされないか、またはその包含モジュールによって限定された方法でエクスポート/オープンされるパッケージを指す。
ダイナミック・モジュール
動的モジュールは、実行時に生成される名前付きモジュールです。 ダイナミック・モジュールで定義されたプロキシ・クラスはカプセル化されており、どのモジュールからもアクセスできません。 動的モジュールのプロキシ・クラスで
Constructor.newInstance(Object...)
を呼び出すと、IllegalAccessException
がスローされます。代わりにProxy.newProxyInstance
メソッドを使用する必要があります。動的モジュールは、プロキシ・クラスのすべてのスーパー・インタフェースのモジュールと、プロキシ・クラスのすべてのパブリック・メソッド・シグネチャによって参照される型のモジュールを読み取ることができます。 スーパー・インタフェースまたは参照される型、たとえば
T
がエクスポートされていないパッケージにある場合、T
のmoduleが更新され、T
のパッケージが動的モジュールにエクスポートされます。複数のプロキシ・インタフェースで重複するメソッド
2つ以上のプロキシ・インタフェースに同じ名前とパラメータ・シグネチャを持つメソッドが含まれている場合、プロキシ・クラス・インタフェースの順序が重要になります。 プロキシ・インスタンス上で重複するメソッドが呼び出された場合、呼出しハンドラに渡される
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
メソッドから正常にスローされないことがあります。- 導入されたバージョン:
- 1.3
- 関連項目:
InvocationHandler
, 直列化された形式
-
-
フィールドのサマリー
フィールド 修飾子と型 フィールド 説明 protected InvocationHandler
h
このプロキシ・インスタンスの呼出しハンドラです。
-
コンストラクタのサマリー
コンストラクタ 修飾子 コンストラクタ 説明 protected
Proxy(InvocationHandler h)
指定された値で、サブクラス(通常は動的プロキシ・クラス)からその呼出しハンドラに新しいProxy
インスタンスを構築します。
-
メソッドのサマリー
すべてのメソッド 静的メソッド 具象メソッド 非推奨のメソッド 修飾子と型 メソッド 説明 static InvocationHandler
getInvocationHandler(Object proxy)
指定されたプロキシ・インスタンスの呼出しハンドラを返します。static Class<?>
getProxyClass(ClassLoader loader, Class<?>... interfaces)
非推奨。名前付きモジュールで生成されたプロキシ・クラスはカプセル化され、モジュール外のコードにはアクセスできません。static boolean
isProxyClass(Class<?> cl)
指定されたクラスがプロキシ・クラスの場合にtrueを返します。static Object
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
メソッドの呼び出しを指定された呼び出しハンドラにディスパッチする、指定されたインタフェースのプロキシ・インスタンスを返します。
-
-
-
フィールドの詳細
-
h
protected InvocationHandler h
このプロキシ・インスタンスの呼出しハンドラです。
-
-
コンストラクタの詳細
-
Proxy
protected Proxy(InvocationHandler h)
指定された値で、サブクラス(通常は動的プロキシ・クラス)からその呼出しハンドラに新しいProxy
インスタンスを構築します。- パラメータ:
h
- このプロキシ・インスタンスの呼出しハンドラ- 例外:
NullPointerException
- 指定された呼び出しハンドラh
がnull
の場合
-
-
メソッドの詳細
-
getProxyClass
@Deprecated public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
非推奨。名前付きモジュールで生成されたプロキシ・クラスはカプセル化され、モジュール外のコードにはアクセスできません。Constructor.newInstance
は、アクセスできないプロキシ・クラスで呼び出されたときにIllegalAccessException
をスローします。 代わりにnewProxyInstance(ClassLoader, Class[], InvocationHandler)
を使用してプロキシ・インスタンスを作成してください。クラス・ローダーとインタフェースの配列の指定されたプロキシ・クラスのjava.lang.Class
オブジェクトを返します。 プロキシ・クラスは指定されたクラス・ローダーにより定義され、指定されたインタフェースをすべて実装します。 指定されたインタフェースのいずれかが非publicである場合、プロキシ・クラスは非publicになります。 インタフェースの同じ順列のプロキシ・クラスがすでにクラス・ローダーにより定義されている場合、既存のプロキシ・クラスが返されます。そうでない場合は、これらのインタフェースのプロキシ・クラスが動的に生成され、クラス・ローダーにより定義されます。- パラメータ:
loader
- プロキシ・クラスを定義するクラス・ローダーinterfaces
- プロキシ・クラスが実装するインタフェースのリスト- 戻り値:
- 指定されたクラス・ローダーで定義され、指定されたインタフェースを実装するプロキシ・クラス
- 例外:
IllegalArgumentException
- パラメータ上のrestrictionsのいずれかに違反した場合SecurityException
- セキュリティ・マネージャsが存在し、次の条件のどれかが満たされる場合:- 指定された
loader
がnull
で、呼出し側のクラス・ローダーがnull
ではなく、RuntimePermission("getClassLoader")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。 - 各プロキシ・インタフェース
intf
について、呼出し側のクラス・ローダーがintf
のクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しがintf
へのアクセスを許可しない。
- 指定された
NullPointerException
-interfaces
配列の引数またはその要素のいずれかがnull
の場合- 関連項目:
- プロキシ・クラスのパッケージとモジュールのメンバーシップ
-
newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
メソッドの呼び出しを指定された呼び出しハンドラにディスパッチする、指定されたインタフェースのプロキシ・インスタンスを返します。次の制限のいずれかに違反すると、
IllegalArgumentException
がスローされます:- 指定された
interfaces
配列内のClass
オブジェクトはすべて、クラスまたはプリミティブ型ではなく、インタフェースを表す必要があります。 interfaces
配列の2つの要素が同一のClass
オブジェクトを参照することはできない。- すべての型のインタフェースは、対応するクラス・ローダーから名前で参照できなければならない。 つまり、クラス・ローダーが
cl
、各インタフェースがi
の場合は、次の式がtrueでなければならない。Class.forName(i.getName(), false, cl) == i
- 指定されたインタフェースのすべてのパブリック・メソッド・シグネチャによって参照される型およびスーパー・インタフェースによって継承される型はすべて、指定されたクラス・ローダーを介して名前で表示される必要があります。
- すべての非公開インタフェースは、指定されたクラス・ローダーによって定義された同じパッケージおよびモジュール内になければならず、非公開インタフェースのモジュールはすべてのインタフェース型にアクセスできます。そうしないと、プロキシ・クラスが定義されているパッケージに関係なく、すべてのインタフェースを実装することができなくなります。
- 指定されたインタフェースが同じ署名を持つ場合、そのようなメソッドの任意の組に対して
- 任意のメソッドの戻り値の型がプリミティブ型またはvoidの場合、それらのメソッドはすべて戻り値の型が同じでなければならない
- そうでない場合、いずれかのメソッドによる戻り値の型は、残りのメソッドによる戻り値の型すべてに対して割当て可能でなければならない
- プロキシ・クラスを作成するときは、Virtual Machineに定義されているクラスの制限を超えてはならない。 たとえば、VMが、クラスが実装できるインタフェース数を65535に制限している場合は、
interfaces
配列のサイズは65535を超えてはならない。
プロキシ・インタフェースは、順番が区別されます。プロキシ・クラスを2回要求したときに、インタフェースの組み合わせが同じで順番が異なる場合は、2つの異なるプロキシ・クラスが作成されます。
- パラメータ:
loader
- プロキシ・クラスを定義するクラス・ローダーinterfaces
- プロキシ・クラスが実装するインタフェースのリストh
- メソッド呼出しのディスパッチ先の呼出しハンドラ- 戻り値:
- 指定されたクラス・ローダーで定義され、指定されたインタフェースを実装するプロキシ・クラスの、指定された呼出しハンドラを持つプロキシ・インスタンス
- 例外:
IllegalArgumentException
- パラメータ上のrestrictionsのいずれかに違反した場合SecurityException
- セキュリティ・マネージャsが存在し、次の条件のどれかが満たされる場合:- 指定された
loader
がnull
で、呼出し側のクラス・ローダーがnull
ではなく、RuntimePermission("getClassLoader")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。 - 各プロキシ・インタフェース
intf
について、呼出し側のクラス・ローダーがintf
のクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しがintf
へのアクセスを許可しない。 - 指定されたプロキシ・インタフェースのいずれかが非publicであり、呼出し側のクラスが非publicインタフェースと同じ実行時パッケージ内にはなく、
ReflectPermission("newProxyInPackage.{package name}")
のアクセス権を使用したs.checkPermission
の呼出しがアクセスを許可しない。
- 指定された
NullPointerException
-interfaces
配列の引数またはその要素のいずれかがnull
の場合、または呼出しハンドラh
がnull
の場合- 関連項目:
- プロキシ・クラスのパッケージとモジュールのメンバーシップ
- 指定された
-
isProxyClass
public static boolean isProxyClass(Class<?> cl)
指定されたクラスがプロキシ・クラスの場合にtrueを返します。- 実装上のノート:
- セキュリティを判定するときにこのメソッドを使用する場合は、信頼性が重要になります。このため、渡されたクラスが
Proxy
を継承しているかどうかを検査してから、追加の検査を行う必要があります。 - パラメータ:
cl
- テストするクラス- 戻り値:
- クラスがプロキシ・クラスの場合は
true
、そうでない場合はfalse
- 例外:
NullPointerException
-cl
がnull
である場合
-
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
指定されたプロキシ・インスタンスの呼出しハンドラを返します。- パラメータ:
proxy
- 呼出しハンドラを返すプロキシ・インスタンス- 戻り値:
- プロキシ・インスタンスの呼出しハンドラ
- 例外:
IllegalArgumentException
- 引数がプロキシ・インスタンスではない場合SecurityException
- セキュリティ・マネージャsが存在し、呼出し側のクラス・ローダーが呼出しハンドラのクラス・ローダーと同じでもその祖先でもなく、s.checkPackageAccess()
の呼出しが呼出しハンドラのクラスのアクセスを許可しない。
-
-