Java Instantiate Class во время выполнения с параметрами
Я использую абстрактную фабрику для возврата экземпляров конкретных подклассов.Я хотел бы создать экземпляр подкласса во время выполнения с заданной строкой конкретного имени класса. Мне также нужно передать параметр конструкторам. Структура классов выглядит следующим образом:
abstract class Parent {
private static HashMap<String, Child> instances = new HashMap<String,Child>()
private Object constructorParameter;
public static Child factory(String childName, Object constructorParam){
if(instances.keyExists(childName)){
return instances.get(childName);
}
//Some code here to instantiate the Child using constructorParam,
//then save Child into the HashMap, and then return the Child.
//Currently, I am doing:
Child instance = (Child) Class.forName(childClass).getConstructor().newInstance(new Object[] {constructorParam});
instances.put(childName, instance);
return instance;
}
//Constructor is protected so unrelated classes can't instantiate
protected Parent(Object param){
constructorParameter = param;
}
}//end Parent
class Child extends Parent {
protected Child(Object constructorParameter){
super(constructorParameter);
}
}
Мой attmept выше вызывает следующее исключение: java.lang.NoSuchMethodException: Child.<init>()
, за которым следует трассировка стека.
Любая помощь ценится. Спасибо!
2 ответа:
Constructor<?> c = Class.forName(childClass).getDeclaredConstructor(constructorParam.getClass()); c.setAccessible(true); c.newInstance(new Object[] {constructorParam});
Метод
getConstructor
принимает аргументыClass
для различения конструкторов. Но он возвращает только открытые конструкторы, поэтому вам понадобитсяgetDeclaredConstructor(..)
. Тогда вам понадобитсяsetAccessible(true)
Ошибка : вы вызываете неправильный конструктор-и компилятор не может вам помочь.
Проблема, с которой вы столкнулись, заключается просто в том, что вы обращались к конструктору с нулевым аргументом, а не к конструктору с аргументами. Помните, что конструкторы в java в конечном счете являются просто методами, хотя и специальными - и с рефлексией все ставки сделаны-компилятор не поможет вам , если вы сделаете что-то глупое. В вашем случае у вас была проблема с областью применения, а также метод выдача подписи одновременно.Как решить эту проблему и никогда не иметь с ней дело снова в этом приложении
Это хорошая идея, чтобы обернуть вызовы конструктора в статический вспомогательный метод, который может быть непосредственно протестирован, а затем поставить тест явно для них в моих модульных тестах, потому что если конструктор изменяется, и вы забываете Обновить код отражения, вы снова увидите, что эти загадочные ошибки снова ползут вверх.
Вы также можете просто вызовите конструктор следующим образом:
public static Child create(Integer i, String s) throws Exception { Constructor c = Class.forName(childClass).getConstructor(new Object[]{Integer.class, String.class}); c.setAccessible(true); Child instance = (Child) c.newInstance(new Object[]{i , s}) ; return instance; }
И, конечно, добавьте к вашим тестам
@Test public void testInvoke() { try{ MyClass.create(1,"test"); } catch(Exception e) { Assert.fail("Invocation failed : check api for reflection classes in " + MyClass.class); } }