通过反射获取给定类的可访问方法列表

时间:2009-12-07 04:18:51

标签: java reflection

有没有办法获得给定类可以访问(不一定是公共)的方法列表?有问题的代码将完全不同。

示例:

public class A {
  public void methodA1();
  protected void methodA2();
  void methodA3();
  private void methodA4();
}

public class B extends A {
  public void methodB1();
  protected void methodB2();
  private void methodB3();
}

对于班级B,我想得到:

  • 所有自己的方法
  • 来自班级methodA1
  • methodA2A
  • methodA3当且仅当班级BA位于同一个包中时

methodA4不应该包含在结果中,因为类B无法访问它。为了再次澄清,需要查找并返回上述方法的代码将在完全不同的类/包中。

现在,Class.getMethods()只返回公共方法,因此不会按我的意愿行事; Class.getDeclaredMethods()仅返回当前类的方法。虽然我当然可以使用后者并且可以手动检查类层次结构来检查可见性规则,但是如果有更好的解决方案,我宁愿不这样做。我在这里错过了一些明显的东西吗?

4 个答案:

答案 0 :(得分:35)

使用Class.getDeclaredMethods()从类或接口获取所有方法(私有或其他方法)的列表。

Class c = ob.getClass();
for (Method method : c.getDeclaredMethods()) {
  if (method.getAnnotation(PostConstruct.class) != null) {
    System.out.println(method.getName());
  }
}

注意:这会排除继承的方法。请使用Class.getMethods()。它将返回所有 public 方法(继承与否)。

要对类可以访问的所有内容(包括继承的方法)进行全面的列表,您需要遍历它扩展的类树。所以:

Class c = ob.getClass();
for (Class c = ob.getClass(); c != null; c = c.getSuperclass()) {
  for (Method method : c.getDeclaredMethods()) {
    if (method.getAnnotation(PostConstruct.class) != null) {
      System.out.println(c.getName() + "." + method.getName());
    }
  }
}

答案 1 :(得分:6)

正如cletus和PSpeed已经回答的那样 - 你需要遍历类的继承树。

这是我这样做的方式,但是没有处理包私有方法:

public static Method[] getAccessibleMethods(Class clazz) {
   List<Method> result = new ArrayList<Method>();

   while (clazz != null) {
      for (Method method : clazz.getDeclaredMethods()) {
         int modifiers = method.getModifiers();
         if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
            result.add(method);
         }
      }
      clazz = clazz.getSuperclass();
   }

   return result.toArray(new Method[result.size()]);
}

我在向后兼容性检查器中使用它,我知道可能受影响的类不会在同一个包中。

答案 2 :(得分:2)

非常确定你必须走上超级班才能得到你想要的东西。毕竟,这就是getMethods()在内部使用getDeclaredMethods()调用的方式(实际上它调用了一个过滤掉非公共方法的私有版本,但它会遍历类树以构建完整列表)。 / p>

很奇怪为什么需要这样的东西。

答案 3 :(得分:1)

关于Cletus答案的观点(我不能在那里发表评论,因为我没有足够的声誉。)无论如何,Cletus的代码对我不起作用(Eclipse也在抱怨它),可能是由于自2009年以来Java的变化。

该行:

for (Class c = ob.getClass(); c != null; c = c.getSuperclass()) {

必须改为:

for (Class<?> c = ob.getClass(); c != null; c = c.getSuperclass()) {

获得任何输出。所以我的完整代码是(包括输入参数类型,修饰符和返回类型):

    for (Class<?> c = scanner.getClass(); c != null; c = c.getSuperclass()) {
      System.out.println(c.getName());          
      for (Method method : c.getMethods()) {
          System.out.println("\t" + Modifier.toString(method.getModifiers()) 
            + " " + method.getName());
          for (Class<?> param: method.getParameterTypes()) {
              System.out.println("\t\t" + param.getName());
          }
          System.out.println("\t\t == returns ==> " + method.getReturnType().getName());
      }
    }