インタフェースInvocationHandler
- 既知のすべての実装クラス:
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
-