Конструктор не найден отражением, когда аргумент является подклассом объявленного типа аргумента конструктора - PullRequest
0 голосов
/ 07 сентября 2018

Я использую рефлексию для создания экземпляров классов для конкретной потребности.

Текущий код похож на:

public final <T> T instanciate(Class<? extends T> a_clazz, Object... args) {

    // Other stuff when no arg...

    Class<?>[] l_argsClasses = getClassesFromObjects(args);
    Constructor<?> constructor = a_clazz.getConstructor(l_argsClasses);
    constructor.newInstance(args)
}

К сожалению, я прочитал, что это не будет работать, если заданные параметры не совсем одного типа в объявлении конструктора.

Поэтому, когда я даю подкласс, конструктор не найден, и я получаю исключение NoSuchMethodException.

Похоже, что здесь нет механизма для обработки полиморфизма.

Пример:

public class A {

}

public class B extends A {

}

public class Foo extends A {
    public Foo(A a) {

    }
}

Будет работать:

instanciate(Foo.class, new A());  // because Foo(A a)

Не будет работать:

instanciate(Foo.class, new B());  // because Foo(B b) does't exists

Есть ли у вас какое-либо решение для решения этой проблемы?

Спасибо

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Пакет java.beans имеет классы Statement и Expression, которые могут выполнять необходимый поиск по правилам подтипа:

Expression e = new Expression(Foo.class, "new", new Object[]{ new B() });
Foo foo = (Foo)e.getValue();

Документация execute метода описывает специальное имя псевдо-метода "new" для вызова конструктора.

0 голосов
/ 07 сентября 2018

Решение, которое я выбрал для использования - это методы, предоставляемые apache.commons.lang.reflect

Предоставляется две разные версии:

  • Необходимо точно соответствовать типам параметров: invokeExactConstructor ()
  • Один соответствует типам параметров по совместимости присваивания: invokeConstructor ()

Я коротко проверил, и это работает. Так что я использую это.

Вот результат:

public final <T> T instanciate(Class<? extends T> clazz, Object... args) {
    try {
        return clazz.cast(ConstructorUtils.invokeConstructor(clazz, args));
    } catch (Exception e) {
        throw new RuntimeException("Failed to instanciate Object", e);
    }
}

Довольно простой код, который хорош

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...