3

ほとんどの人がやりたいこととは正反対のことが必要です。つまり、className と methodName を持つ StackTraceElement があります。メソッドは特定のクラスが実装するインターフェイスに属しているため、メソッドがどのインターフェイスで発生したかをメソッドに問い合わせる方法が必要です。

私は呼び出すことができ、Class.forName(className)また呼び出すこともできますが、元のインターフェイスではなく、言及されたクラスの名前で返されます。すべてのクラスのインターフェイスを繰り返し処理して、その特定のメソッドを見つけることはしたくありません。これにより、パフォーマンスが実質的に無効になります。clazz.getMethod(methodName)method.getDeclaringClass()

--

基本的に、これは従来のブロードキャスト メカニズムです。ブロードキャスター クラスにはハッシュマップが含まれます。キーはインターフェイスであり、値は実装クラスのリストです。ブロードキャスターは、各メソッドがハッシュマップから実装クラスを取得し、それらを反復処理して、各実装クラスで同じメソッドを呼び出すように、同じインターフェースを実装します。

--

ここに追加して申し訳ありませんが、コメント内に追加するには少し長すぎます:

私の解決策は、アンドレアスが言及しているものに似ていました:

StackTraceElement invocationContext = Thread.currentThread().getStackTrace()[2];
Class<T> ifaceClass = null;
Method methodToInvoke = null;
for (Class iface : Class.forName(invocationContext.getClassName()).getInterfaces()) {
  try {
    methodToInvoke = iface.getMethod(invocationContext.getMethodName(), paramTypes);
    ifaceClass = iface;
    continue;
  } catch (NoSuchMethodException e) {
    System.err.println("Something got messed up.");
  }
}

like 構造を使用するinvocationContextとインターセプターを作成できるため、トランスミッターには、実装本体が空のアノテーション付きメソッドのみを含めることができます。

4

3 に答える 3

3

className と methodName を持つ StackTraceElement があります。
メソッドがどのインターフェイスで発生したかをメソッドに問い合わせる方法が必要
です。すべてのクラスのインターフェイスを反復してその特定のメソッドを見つけたくないので、パフォーマンスが実質的に無効になります。

最初に、すべてのクラス インターフェイスを反復処理することが、ユースケースで本当にパフォーマンスが重要かどうかを確認します。通常、スタック トレース エレメントがある場合は、パフォーマンスがそれほど重要ではない例外的な状態になっています。Class.getInterfaces()次に、インターフェイスをトラバースし、各インターフェイスの宣言されたメソッドをクエリするために使用できます。たとえば、次のようになります。

class MethodQuery {
   private Set<Class<?>> result = new HashSet<>();
   private String theMethodName;

   private void traverse(Class<?> cls) {
      for (Class<?> c : cls.getInterfaces()) {
         for (Method m : c.getDeclaredMethods()) {
            if (theMethodName.equals(m.getName())) {
               result.add(c);
            }
         }

         traverse(c);
      }
   }

   public Set<Class<?>> getInterfacesForMethod(Class<?> cls, String methodName) {
      result.clear();
      theMethodName = methodName;
      traverse(cls);
      return result;
   }
}

次に、メソッドが宣言するインターフェイスを次のようにクエリできます。

MethodQuery methodQuery = new MethodQuery();
Set<Class<?>> result = 
    methodQuery.getInterfacesForMethod(java.util.Vector.class, "addAll");
System.out.println(result);

結果:

[interface java.util.Collection, interface java.util.List]
于 2013-04-25T10:20:53.197 に答える
2

パフォーマンスに敏感な状況でこれが必要になる理由は想像できませんが、検索結果をキャッシュすることはできます。注: 同じメソッドが多くのインターフェースからメソッドを実装する場合があります。

于 2013-04-24T11:24:12.903 に答える
1

すべてのクラスのインターフェイスを繰り返し処理して、その特定のメソッドを見つけることはしたくありません。これにより、パフォーマンスが実質的に無効になります。

代替案はないと思います。

(しかし、Peter Lawrey の言うことを反映するために、キャッシングは役に立ちます...パフォーマンスが重要な場合は、一般的にリフレクションを避ける必要があります。)

また、次の点に注意してください。

  • 特定のメソッドがどのインターフェイスでも宣言されていない可能性があります。
  • 特定のメソッドナイトは、複数のインターフェース、または複数のパスを介して継承されるインターフェースで宣言できます。

スキームが真に一般的であるためには、これらのことを考慮に入れる必要があります。


1 つのメソッドが 1 つのインターフェイスだけに属することが保証されます。

たとえそうであっても ...

于 2013-04-24T11:28:44.693 に答える