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

395
13 октября 2017, 13:45

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

Answer 1

Есть следующие классические пути.

В качестве примера используем такой максимальный конструктор

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<Int> numbers){код}

Либо использовать конструкцию VARARGS:

public MyNumbers(Int... numbers){код}

В принципе никто не мешает передавать List<Object>, но это если совсем безнадёга - так делать не надо.

Если аргументы заранее известны, их много, но неизвестно, какие будут заданы, то стоит использовать шаблон проектирования 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();
Answer 2

Нет. В 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()) {
                 //...инициализируем как нужно
                 //Тут вы как-нибудь сами
            }
        }
    }
}
...

Однако учтите - обычная рефлексия ужасно бьет по производительности. Если для вас это критично, ищите способы ускорения (например) или другие решения.

Answer 3

Есть такой способ хакинга (заранее предупреждаю, что это антипаттерн):

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

Еще раз - так не рекомендуется делать, но иногда так делается. Сам лично когда то делал такую поделушку.

READ ALSO
Конвертация Map в объект через Jpa

Конвертация Map в объект через Jpa

Есть Map<String, Object> с полями объектаНужно конвертировать эту мапу в объект так как это сделал бы Hibernate, используя колонки @Column(name="

294
Посчитать средний и общий бал

Посчитать средний и общий бал

Есть такой вот код, в условиях задачи сказано: Display the average and total rating of all student

264
Ошибочная сериализация полей с Gson

Ошибочная сериализация полей с Gson

У меня в обьекте есть поле:

237
Вопрос по защите приложения

Вопрос по защите приложения

Вообще никак нельзя определить, что приложение декомпилируетсяДекомпилятор работает с кодом как с потоком байтов, а не исполняемой сущностью

273