如何找到一个类中实现了哪些Java接口的方法?

3
我需要做与大多数人想要完成的相反的操作:我有一个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.");
  }
}

使用类似于invocationContext的结构可以使拦截器生效,这样传输器只需包含带有空实现体的注释方法。

2
你尝试过在你的使用场景中是否Class.getInterfaces()真的很关键吗? - Andreas Fester
保证一个方法只属于一个接口。 - András Hummer
Andreas,请您把您的评论加入回答中,可以吗?我最终选择了Class.getInterfaces(),似乎解决了问题。 - András Hummer
3个回答

3
我有一个包含类名和方法名的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]

2

我无法想象为什么在性能敏感的情况下您需要这个,但您可以缓存您搜索的结果。注意:同一方法可能实现多个接口中的方法。


1
我不想遍历所有类的接口以找到特定方法,这实际上会使性能降至零。
我认为没有其他选择。
(但要回应Peter Lawrey所说的,缓存会有所帮助...如果性能很重要,应该避免使用反射。)
还请注意:
- 给定的方法可能没有在任何接口中声明。 - 给定的方法可能在多个接口中声明,或者在通过多个路径继承的接口中声明。
如果您的方案要真正通用,就必须考虑这些事情。

保证一个方法仅属于一个接口。

即便如此...


一个给定的方法只在一个接口中声明,但是这个接口被多个类实现。其中一个类已经包含了一个HashMap,其中包含了其余实现类,而接口则是键。这就是为什么我需要这个接口,这样我就可以将每个方法调用广播到所有其他实现类。 - András Hummer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接