Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Динамическое создание конструктора

#java


В Java программе необходимо создать объект, но заранее не известно сколько и какие
поля будут участвовать в конструкторе. Есть ли возможность во время выполнения добавлять
к классу конструктор с необходимым набором параметров? 
    


Ответы

Ответ 1



Есть такой способ хакинга (заранее предупреждаю, что это антипаттерн): Задаемся некой структурой данных описывающих поведение гипотетического конструктора (в реалии конечно же класс с заданным конструктором) - нечто типа псевдоязыка - вполне сойдет какой-нибудь xml/json Парсим псевдоязык и генерируем на лету исходник класса Через ToolProvider вызываем в рантайме компилятор Javа Далее через ClassLoader загружаем объектник класса Далее уже все как обычно: у нас есть ссылка на класс, вызываем через рефлексию его конструктор. Еще раз - так не рекомендуется делать, но иногда так делается. Сам лично когда то делал такую поделушку.

Ответ 2



Есть следующие классические пути. В качестве примера используем такой максимальный конструктор public Person(String name, Int age, Double weight) Если вариантов использования конструктора ограниченное количество (т.е., например, всего три варианта: name+age,+weight, name+age, name+weight), то правильным путем будет создание трех конструкторов: public Person(String name, Int age, Double weight){код} public Person(String name, Int age){ this(name, age, 25.4); } public Person(String name, Double weight){ this(name, 78, weight); } Если прямо совсем неопределенное количество аргументов одного класса, то имеет смысл либо передавать их коллекцию: public MyNumbers(List numbers){код} Либо использовать конструкцию VARARGS: public MyNumbers(Int... numbers){код} В принципе никто не мешает передавать List, но это если совсем безнадёга - так делать не надо. Если аргументы заранее известны, их много, но неизвестно, какие будут заданы, то стоит использовать шаблон проектирования Builder Если совсем упрощенно, то: class PersonBuilder{ private String name = ""; private Int age = 78; private Double weight = 25.4; public PersonBuilder setName(String name){ this.name = name; return this; } // для двух других параметров аналогично public Person build(){ return new Person(name, age, weight); } } Person person = (PersonBuilder()).setName("John").setWeight(22.7).build();

Ответ 3



Нет. В Java методы, к сожалению для многих, методы не являются обьектами, поэтому их нельзя произвольно вставлять/удалять/переделывать во времени выполнения. Наиболее близким к вашей задаче альтернативным решением является реализация рефлексивного конструктора, принимающего два массива: один с названиями полей, другой - с соотвествующими значениями для инициализации. ... public SomeClass (String[] fields, Object[] valuesForInit) { //Получаем класс и поля Class clazz = SomeClass.class; Field[] classFields = clazz.getFields(); //Перебираем список всех полей и список нужных для инициализации for (int i = 0; i < fields.length(); i++) { for (Field classField : classFields) { //Если поле нужно инициализировать и значение соответствует типу поля... if (field[i] == classField.getName() && valuesForInit[i] instanceof classField.getType()) { //...инициализируем как нужно //Тут вы как-нибудь сами } } } } ... Однако учтите - обычная рефлексия ужасно бьет по производительности. Если для вас это критично, ищите способы ускорения (например) или другие решения.

Комментариев нет:

Отправить комментарий