Получение списка доступных методов для данного класса с помощью отражения - PullRequest
28 голосов
/ 07 декабря 2009

Есть ли способ получить список методов, которые были бы доступны (не обязательно общедоступны) для данного класса? Код, о котором идет речь, будет совершенно другого класса.

Пример:

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 и methodA2 из класса A
  • methodA3 тогда и только тогда, когда класс B находится в том же пакете, что и A

methodA4 никогда не следует включать в результаты, поскольку они недоступны для класса B. Чтобы еще раз уточнить, код, который должен найти и вернуть вышеуказанные методы, будет находиться в совершенно другом классе / пакете.

Теперь Class.getMethods() возвращает только открытые методы и, следовательно, не будет делать то, что я хочу; Class.getDeclaredMethods() возвращает только методы для текущего класса. Хотя я, конечно, могу использовать последнее и пройтись по иерархии классов, проверяя правила видимости вручную, я бы предпочел, чтобы не было лучшего решения. Я что-то упускаю здесь явно очевидное?

Ответы [ 4 ]

35 голосов
/ 07 декабря 2009

Используйте Class.getDeclaredMethods(), чтобы получить список всех методов (частных или других) из класса или интерфейса.

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

Примечание: это исключает унаследованные методы. Для этого используйте Class.getMethods(). Он вернет все публичные методы (унаследованные или нет).

Чтобы сделать исчерпывающий список всего, к чему класс может получить доступ (включая унаследованные методы), вам нужно пройти по дереву классов, которые он расширяет. Итак:

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());
    }
  }
}
6 голосов
/ 28 октября 2010

Как уже ответили Клетус и 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 голосов
/ 07 декабря 2009

Уверен, вам придётся пройтись по суперклассам, чтобы получить то, что вы хотите. В конце концов, это то, что getMethods () делает с внутренним вызовом getDeclaredMethods () (вроде: он на самом деле вызывает закрытую версию, которая отфильтровывает непубличные методы, но перебирает дерево классов для построения полного списка).

Любопытно, зачем такая вещь нужна.

1 голос
/ 25 июля 2017

Точка ответа Клетуса (я не могу комментировать, потому что мне не хватает репутации.). В любом случае, код Cletus у меня не работал (Eclipse также жаловался на это), вероятно, из-за изменений в Java с 2009 года.

Линия:

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());
      }
    }        
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...