モジュール java.base
パッケージ java.lang.reflect

インタフェースInvocationHandler

既知のすべての実装クラス:
CompositeDataInvocationHandler, EventHandler, MBeanServerInvocationHandler, RemoteObjectInvocationHandler

public interface InvocationHandler
InvocationHandlerは、プロキシ・インスタンスの呼出しハンドラが実装するインタフェースです。

プロキシ・インスタンスには、それぞれに関連した呼出しハンドラがあります。 プロキシ・インスタンスでメソッドが呼び出されると、メソッドの呼出しが符号化され、各プロキシ・インスタンスの呼出しハンドラのinvokeメソッドにディスパッチされます。

導入されたバージョン:
1.3
関連項目:
Proxy
  • メソッドのサマリー

    修飾子と型
    メソッド
    説明
    invoke​(Object proxy, Method method, Object[] args)
    プロキシ・インスタンスでメソッド呼出しを処理し、その結果を返します。
    static Object
    invokeDefault​(Object proxy, Method method, Object... args)
    指定されたパラメータを使用して、指定されたproxyインスタンスの指定されたデフォルト・メソッドを呼び出します。
  • メソッドの詳細

    • invoke

      Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      プロキシ・インスタンスでメソッド呼出しを処理し、その結果を返します。 関連したプロキシ・インスタンスでメソッドが呼び出されると、このメソッドは呼出しハンドラで呼び出されます。
      パラメータ:
      proxy - メソッドが呼び出されるプロキシ・インスタンス
      method - プロキシ・インスタンスで呼び出されたインタフェース・メソッドに対応するMethodインスタンス。 Methodオブジェクトの宣言クラスは、このメソッドが宣言されたインタフェースです。プロキシ・クラスがメソッドを継承するプロキシ・インタフェースのスーパー・インタフェースのこともある。
      args - プロキシ・インスタンスでのメソッド呼出し時に渡される引数値を格納するオブジェクト配列。インタフェース・メソッドが引数を取らない場合はnull プリミティブ型の引数は、java.lang.Integerjava.lang.Booleanなどの適切なプリミティブ・ラッパー・クラスのインスタンスにラップされる。
      戻り値:
      プロキシ・インスタンスでのメソッド呼出しからの戻り値。 インタフェース・メソッドの宣言された戻り値の型がプリミティブ型の場合、このメソッドの戻り値は対応するプリミティブ・ラッパー・クラスのインスタンスである必要がある。それ以外の場合は、宣言された戻り値の型に割当て可能な型である必要がある。 このメソッドの戻り値がnullで、インタフェース・メソッドの戻り値がプリミティブ型の場合、NullPointerExceptionがプロキシ・インスタンスでのメソッド呼出しによってスローされる。 これ以外のケースで、このメソッドの戻り値と前述のようなインタフェース・メソッドの宣言された戻り値の型との間に互換性がない場合、ClassCastExceptionがプロキシ・インスタンスでのメソッド呼出しによってスローされる。
      例外:
      Throwable - プロキシ・インスタンスでのメソッド呼び出しからスローされる例外。 この例外のタイプは、インタフェース・メソッドのthrows節に宣言される例外タイプか、または、非チェック例外タイプのjava.lang.RuntimeExceptionまたはjava.lang.Errorに割り当てられなければならない。 このメソッドによってスローされるチェック例外が、インタフェース・メソッドのthrows節に宣言された例外タイプに割り当てられない場合、このメソッドがスローした例外を格納するUndeclaredThrowableExceptionがプロキシ・インスタンスでのメソッド呼出しによってスローされることになる。
      関連項目:
      UndeclaredThrowableException
    • invokeDefault

      static Object invokeDefault(Object proxy, Method method, Object... args) throws Throwable
      指定されたパラメータを使用して、指定されたproxyインスタンスの指定されたデフォルト・メソッドを呼び出します。 指定されたmethodは、proxyのクラスのプロキシ・インタフェースで宣言されているか、そのスーパー・インタフェースから直接または間接的に継承されたデフォルト・メソッドである必要があります。

      このメソッドを呼び出すと、invokespecial命令がプロキシ・クラスから実行されたかのように動作し、プロキシ・インタフェースのデフォルト・メソッドをターゲットにします。 これは呼出しと同等です : Xがプロキシ・インタフェースであり、X.super::m(A*)へのコールが特定のmethodに解決されるX.super.m(A* a)

      例: インタフェースABの両方で、メソッドmのデフォルト実装が宣言されています。 Interface 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);
                   }
               });
       
      プロキシ・インスタンスがABの両方を実装し、どちらも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またはmethodnullの場合
      Throwable - defaultメソッドによってスローされるもの
      Java Virtual Machine仕様を参照してください:
      「5.4.3.メソッド解決」
      導入されたバージョン:
      16