#java #reflection
#java #отражение
Вопрос:
Я работал над тем, чтобы лучше понять инструменты отражения Java, и сейчас пытаюсь создать новый экземпляр класса с конструктором, который был выбран пользователем в выпадающем списке.
//ask user what to name the new instance of chosen Class ( passed into this method )
String instanceName = JOptionPane.showInputDialog(null, "Under what name would you like to store this Instance?",
"Create an Instance of a Class", JOptionPane.QUESTION_MESSAGE);
Object chosenC = JOptionPane.showInputDialog(null, "Please choose a Constructor for" chosenClass,
"Create an Instance of a Class", 3, null, getConstructors(chosenClass), JOptionPane.QUESTION_MESSAGE);
Constructor c = (Constructor)chosenC;
Class[] params = c.getParameterTypes(); //get the parameters of the chosen Constructor
try {
//create the instance with the correct constructor
instance = c.newInstance((Object[])params);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e){
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Прямо сейчас я получаю исключение ArgumentTypeMismatch, если я выбираю что-либо, кроме конструктора по умолчанию (без параметров). Я упускаю что-то вопиюще очевидное?
Спасибо за любую помощь.
РЕДАКТИРОВАТЬ Спасибо всем за ваши ответы.
Но тогда как бы я запросил параметры? Если я получу длину массива params, то мне нужно будет определить, к какому типу класса относится каждый индекс, и попросить пользователя ввести значение в правильной форме? Тогда как бы я передал этот новый массив в параметр newInstance?
Комментарии:
1. Обычно такого рода динамическое создание объекта лучше всего выполнять с классами, у которых есть конструктор по умолчанию. Таким образом, вы можете создать объект, а затем позже задать любые параметры, которые вы хотите, с помощью установщиков и т.д. В этом случае нужно будет выполнить цикл, хотя все
params
и для каждого класса там создаютсяclazz.newInstance(...)
… что может быть приятной бесконечной бездной2. @Frank71 — это приложение для разработчиков или у вас есть конечный пользователь? В последнем случае я бы не оставил определение поведения на усмотрение Reflection API, а указал бы в коде конструктор / поведение каждой опции из выпадающего списка.
Ответ №1:
Задан класс с конструктором, подобным этому:
MyClass(String s, Long l)
Ваш код фактически вызывает следующее:
new MyClass(String.class, Long.class)
Где он должен вызывать:
new MyClass("", 1L)
Вам нужен экземпляр каждого из типов параметров конструктора, но вы передаете только классы. Интересно, что если ваш конструктор принимает только экземпляры Class
, это сработало бы, но дало бы неожиданные результаты.
Комментарии:
1. Хороший пример. но я должен придраться к последнему предложению. Это скомпилировалось бы, но, скорее всего, это было бы не то, чего кто-либо хотел, поэтому говорить «это сработало бы», я думаю, не совсем точно.
Ответ №2:
Вы передаете класс [] конструктору, когда вам нужен массив экземпляров. Например, если вашим конструктором является Foo(String), вы хотите сделать что-то вроде
c.newInstance(new Object[] {"aString"});
То, что вы делаете, это,
c.newInstance(new Object[] {String.class});
Ответ №3:
Ваши params
должны быть аргументами, переданными конструктору. Все ваши параметры являются ссылками на класс, поэтому, если все ваши параметры не являются Class a, Class b, Class c
, это не сработает.
Возможно, вам следует разрешить пользователю определять, какими должны быть значения.
Ответ №4:
Вызов:
instance = c.newInstance((Object[])params);
здесь вы должны передать аргументы для конструктора, а не типы, которые вы получаете при вызове:
Class[] params = c.getParameterTypes();
Если ваш конструктор является:
public MyConstructor( int foo, String bar ) {
//...
}
затем вы должны передать параметры как (например):
Object [] params = new Object [] { 10, "someString" };
Ответ №5:
Когда вы вызываете newInstance
экземпляр конструктора, вам нужно передать параметры правильных классов. Вы предоставляете Class
сами объекты в качестве параметров.
Например, если ваш конструктор является
Person(String firstName, String lastName)
Вы бы вызвали
new Person("John", "Doe");
Или, в терминах отражения
c.newInstance("John", "Doe");
Но ваш код на самом деле выполняет
c.newInstance(String.class, String.class);
Если вы хотите, чтобы пользователь выбрал конструктор, вам также нужно будет запросить у него некоторые параметры.