Проблема в GetDeclaredMethods (Java)

У меня есть небольшая проблема в моем коде

У меня есть 2 класса

public class A {

     public A foo(int a) {return new A();}
}

public class B extends A{

     public B foo(int x){ return new B();}
}

теперь в моем коде я хочу распечатать только метод, который был объявлен в классе B

таким образом

B b = new B();

Method[] m = b.getClass().getDeclaredMethods();

for (int i = 0; i < m.length; i++) {

System.out.print(m[i].getName());   
}

почему вывод

foo

foo

почему GetDeclaredMethods находит также нечто в класс? как я могу зафиксировать его?

спасибо

8
задан rsp 25 December 2009 в 15:47
поделиться

6 ответов

Проблема возникает из-за ковариантных типов возвращаемых данных двух ваших методов. Поскольку у вас есть ковариантный тип возвращаемого значения (тип возвращаемого значения B - это B, а не A, в отличие от суперкласса), Java под капотом генерирует отдельный метод с исходным типом возврата, чтобы действовать как мост между спецификацией байт-кода до 1.5 и новое поведение языка Java 1.5.

Для проверки следует использовать метод isBridge () , поскольку он точно выражает то, что вы собираетесь исключить. Таким образом, окончательный код будет выглядеть примерно так:

Method[] methods = B.class.getDeclaredMethods();

for (Method method : methods) {

   if (!method.isBridge()) {
       System.out.println(method.getName());
   }   
}
18
ответ дан 5 December 2019 в 07:58
поделиться

По умолчанию getDeclaredMethods () возвращает все методы для данного класса, а также его родительские классы и интерфейсы. Однако объект Method позволяет вам проверить, к какому классу принадлежит Method , вызвав getDeclaringClass () для этого Method . Поэтому, когда вы циклически перебираете все объекты Method , вы можете добавить логику для печати метода, только если он принадлежит классу B .

Method[] m = b.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
  if (m[i].getDeclaringClass().equals(B.class)) {
    System.out.print(m[i].getName());
  }
}

EDIT: Приведенный выше код не работает должным образом - он возвращает B как класс объявления всех методов. Метод isSynthetic () , похоже, работает должным образом, возвращая истину для замещенного метода (который пришел из A ), но ложь для той, что пришла из B . Так что следующий код может быть тем, что вы ищете:

Method[] m = b.getClass().getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
  if (!m[i].isSynthetic()) {
    System.out.print(m[i]);
  }
}
2
ответ дан 5 December 2019 в 07:58
поделиться

Потому что B.foo и A.foo - это разные методы. Если вы хотите переопределить метод A.foo, тогда метод B.foo должен возвращать класс A.

1
ответ дан 5 December 2019 в 07:58
поделиться

Вы можете вызвать m.getDeclaringClass (), чтобы узнать, является ли это метод из класса A или класс B.

0
ответ дан 5 December 2019 в 07:58
поделиться

Это может сработать:

A a = new A();
B b = new B();

List<Method> aMethods = Arrays.asList(a.getClass().getMethods());
List<Method> bMethods = Arrays.asList(b.getClass().getMethods());

for ( Method m : bMethods )
{
  if( ! aMethods.contains(m) )
  {
  //Your action code here
  }
}
0
ответ дан 5 December 2019 в 07:58
поделиться

Когда вы говорите if( ! aMethods.contains(m) ) содержит сравнение по name? arguments type? return value type? потому что единственное отличие от метода-розыскивателя - тип возвращаемого ковариационного типа...

0
ответ дан 5 December 2019 в 07:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: