- 既知のすべての実装クラス:
CompositeDataInvocationHandler
,EventHandler
,MBeanServerInvocationHandler
,RemoteObjectInvocationHandler
public interface InvocationHandler
InvocationHandler
は、プロキシ・インスタンスの呼出しハンドラが実装するインタフェースです。
プロキシ・インスタンスには、それぞれに関連した呼出しハンドラがあります。 プロキシ・インスタンスでメソッドが呼び出されると、メソッドの呼出しが符号化され、各プロキシ・インスタンスの呼出しハンドラのinvoke
メソッドにディスパッチされます。
- 導入されたバージョン:
- 1.3
- 関連項目:
-
メソッドのサマリー
-
メソッドの詳細
-
invoke
プロキシ・インスタンスでメソッド呼出しを処理し、その結果を返します。 関連したプロキシ・インスタンスでメソッドが呼び出されると、このメソッドは呼出しハンドラで呼び出されます。- パラメータ:
proxy
- メソッドが呼び出されるプロキシ・インスタンスmethod
- プロキシ・インスタンスで呼び出されたインタフェース・メソッドに対応するMethod
インスタンス。Method
オブジェクトの宣言クラスは、このメソッドが宣言されたインタフェースです。プロキシ・クラスがメソッドを継承するプロキシ・インタフェースのスーパー・インタフェースのこともある。args
- プロキシ・インスタンスでのメソッド呼出し時に渡される引数値を格納するオブジェクト配列。インタフェース・メソッドが引数を取らない場合はnull
。 プリミティブ型の引数は、java.lang.Integer
やjava.lang.Boolean
などの適切なプリミティブ・ラッパー・クラスのインスタンスにラップされる。- 戻り値:
- プロキシ・インスタンスでのメソッド呼出しからの戻り値。 インタフェース・メソッドの宣言された戻り値の型がプリミティブ型の場合、このメソッドの戻り値は対応するプリミティブ・ラッパー・クラスのインスタンスである必要がある。それ以外の場合は、宣言された戻り値の型に割当て可能な型である必要がある。 このメソッドの戻り値が
null
で、インタフェース・メソッドの戻り値がプリミティブ型の場合、NullPointerException
がプロキシ・インスタンスでのメソッド呼出しによってスローされる。 これ以外のケースで、このメソッドの戻り値と前述のようなインタフェース・メソッドの宣言された戻り値の型との間に互換性がない場合、ClassCastException
がプロキシ・インスタンスでのメソッド呼出しによってスローされる。 - 例外:
Throwable
- プロキシ・インスタンスでのメソッド呼び出しからスローされる例外。 この例外のタイプは、インタフェース・メソッドのthrows
節に宣言される例外タイプか、または、非チェック例外タイプのjava.lang.RuntimeException
またはjava.lang.Error
に割り当てられなければならない。 このメソッドによってスローされるチェック例外が、インタフェース・メソッドのthrows
節に宣言された例外タイプに割り当てられない場合、このメソッドがスローした例外を格納するUndeclaredThrowableException
がプロキシ・インスタンスでのメソッド呼出しによってスローされることになる。- 関連項目:
-
invokeDefault
指定されたパラメータを使用して、指定されたproxy
インスタンスの指定されたデフォルト・メソッドを呼び出します。 指定されたmethod
は、proxy
のクラスのプロキシ・インタフェースで宣言されているか、そのスーパー・インタフェースから直接または間接的に継承されたデフォルト・メソッドである必要があります。このメソッドを呼び出すと、
invokespecial
命令がプロキシ・クラスから実行されたかのように動作し、プロキシ・インタフェースのデフォルト・メソッドをターゲットにします。 これは呼出しと同等です :X
がプロキシ・インタフェースであり、X.super::m(A*)
へのコールが特定のmethod
に解決されるX.super.m(A* a)
。例: インタフェース
A
とB
の両方で、メソッドm
のデフォルト実装が宣言されています。 インタフェースC
は、A
を拡張し、スーパー・インタフェースA
からデフォルトのメソッドm
を継承します。
次の例では、interface A { default T m(A a) { return t1; } } interface B { default T m(A a) { return t2; } } interface C extends A {}
A
を実装するプロキシ・インスタンスを作成し、デフォルトのメソッドA::m
を呼び出します。
プロキシ・インスタンスがObject proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class }, (o, m, params) -> { if (m.isDefault()) { // if it's a default method, invoke it return InvocationHandler.invokeDefault(o, m, params); } });
A
とB
の両方を実装し、どちらもm
メソッドのデフォルト実装を提供する場合、起動ハンドラはinvokeDefault
メソッドを介してA::m
またはB::m
にメソッド呼出しをディスパッチできます。 たとえば、次のコードはメソッド呼出しをB::m
に委任します。
プロキシ・インスタンスが、そのスーパー・インタフェースObject proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class, B.class }, (o, m, params) -> { if (m.getName().equals("m")) { // invoke B::m instead of A::m Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, bMethod, params); } });
A
からデフォルト・メソッドm
を継承するC
を実装する場合、Method
オブジェクト引数がデフォルト・メソッドA::m
を表す呼出しハンドラinvoke
に"m"
のインタフェース・メソッド呼出しがディスパッチされます。
このObject proxy = Proxy.newProxyInstance(loader, new Class<?>[] { C.class }, (o, m, params) -> { if (m.isDefault()) { // behaves as if calling C.super.m(params) return InvocationHandler.invokeDefault(o, m, params); } });
proxy
でのメソッド"m"
の呼出しは、C.super::m
が呼び出されたかのように動作し、A::m
の呼出しに解決されます。デフォルト・メソッドを追加したり、メソッドを抽象メソッドからデフォルト・メソッドに変更すると、既存のコードが
invokeDefault
をコールしてデフォルト・メソッドを呼び出そうとした場合に例外が発生する可能性があります。 たとえば、C
がデフォルトのメソッドm
を実装するように変更された場合は、次のようになります:
変更されたinterface C extends A { default T m(A a) { return t3; } }
C
を使用してプロキシ・インスタンスproxy
を作成する前述のコードは、例外なしで実行され、A::m
のかわりにC::m
がコールされます。次に、
C
のプロキシ・インスタンスを作成し、起動ハンドラがinvokeDefault
メソッドをコールしてA::m
を起動する別の例を示します :
前述のコードは古いバージョンのC c = (C) Proxy.newProxyInstance(loader, new Class<?>[] { C.class }, (o, m, params) -> { if (m.getName().equals("m")) { // IllegalArgumentException thrown as {@code A::m} is not a method // inherited from its proxy interface C Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, aMethod params); } }); c.m(...);
C
で正常に実行され、A::m
が起動されます。 新しいバージョンのC
で実行する場合、C
が同じメソッドの実装をオーバーライドし、A::m
にプロキシ・インスタンスからアクセスできないため、前述のコードはIllegalArgumentException
で失敗します。- APIのノート:
proxy
パラメータのタイプはProxy
ではなくObject
であるため、InvocationHandler::invoke
の実装ではキャストを必要とせずに直接コールできます。- パラメータ:
proxy
- デフォルト・メソッドが呼び出されるProxy
インスタンスmethod
- プロキシ・クラスのプロキシ・インタフェースで宣言されたか、そのスーパー・インタフェースから直接または間接的に継承されたデフォルト・メソッドに対応するMethod
インスタンスargs
- メソッド呼出しに使用されるパラメータ。メソッドが必要とする仮パラメータの数がゼロの場合はnull
になります。- 戻り値:
- メソッド呼出しから返される値
- 例外:
IllegalArgumentException
- 次のいずれかの条件がtrue
の場合:proxy
が「プロキシ・インスタンス」ではない場合- 指定された
method
がプロキシ・クラスのプロキシ・インタフェースで宣言されたデフォルト・メソッドではなく、そのスーパー・インタフェースから継承されていない場合 - 指定された
method
がプロキシ・インタフェースによって直接または間接的にオーバーライドされ、指定されたメソッドへのメソッド参照が指定されたmethod
に解決されない場合 - 指定された
args
配列の長さが、呼び出されるメソッドのパラメータ数と一致しない場合 - いずれかの
args
要素は、対応するメソッド・パラメータ型がプリミティブ型の場合、または可能なかぎりアン・ボクシング後に、対応するメソッド・パラメータ型にargs
要素を割り当てることができない場合、アン・ボクシング変換に失敗します。
IllegalAccessException
- 指定されたデフォルト・メソッドの宣言クラスに呼出し側クラスからアクセスできない場合NullPointerException
-proxy
またはmethod
がnull
の場合Throwable
- defaultメソッドによってスローされるもの- Java Virtual Machine仕様を参照してください:
-
「5.4.3.メソッド解決」
- 導入されたバージョン:
- 16
-