Возможно ли выполнить вычисление перед супер() в конструкторе?
Учитывая, что у меня есть класс Base, у которого есть единственный конструктор аргументов с объектом TextBox в качестве аргумента. Если у меня есть класс Simple следующего вида:
public class Simple extends Base {
public Simple(){
TextBox t = new TextBox();
super(t);
//wouldn't it be nice if I could do things with t down here?
}
}
Я получаю сообщение об ошибке, указывающее, что вызов супер должен быть первым вызовом в конструкторе. Однако, как ни странно, я могу это сделать.
public class Simple extends Base {
public Simple(){
super(new TextBox());
}
}
Почему это разрешено, но первый пример - нет? Я могу понять, что нужно сначала настроить подкласс и, возможно, не позволить создавать объектные переменные до вызова суперконструктора. Но t - явно метод (локальная) переменная, так почему бы не позволить это?
Есть ли способ обойти это ограничение? Есть ли хороший и безопасный способ держать переменные в вещах, которые вы могли бы создать, прежде чем звонить супер, но ПОСЛЕ того, как вы вошли в конструктор? Или, в более общем плане, позволяя выполнить вычисление до того, как супер действительно вызывается, но внутри конструктора?
Спасибо.
Ответы
Ответ 1
Да, для вашего простого случая есть обходной путь. Вы можете создать частный конструктор, который принимает TextBox
в качестве аргумента и вызывает это из вашего публичного конструктора.
public class Simple extends Base {
private Simple(TextBox t) {
super(t);
// continue doing stuff with t here
}
public Simple() {
this(new TextBox());
}
}
Для более сложных вещей вам необходимо использовать factory или статический метод factory.
Ответ 2
У меня была такая же проблема с вычислением перед супервызовом. Иногда вы хотите проверить некоторые условия перед вызовом super()
. Например, у вас есть класс, который использует много ресурсов при создании. подкласс требует дополнительных данных и может сначала проверить их, прежде чем вызывать супер-конструктор. Существует простой способ решения этой проблемы. может показаться немного странным, но он работает хорошо:
Используйте частный статический метод внутри вашего класса, который возвращает аргумент супер-конструктора и делает свои проверки внутри:
public class Simple extends Base {
public Simple(){
super(createTextBox());
}
private static TextBox createTextBox() {
TextBox t = new TextBox();
t.doSomething();
// ... or more
return t;
}
}
Ответ 3
требуется на этом языке, чтобы гарантировать, что суперкласс надежно сконструирован первым. В частности, "Если конструктор явно не вызывает конструктор суперкласса, компилятор Java автоматически вставляет вызов конструктору без аргументов суперкласса".
В вашем примере суперкласс может полагаться на состояние t
во время построения. Вы всегда можете попросить копию позже.
Здесь подробно обсуждается .
Ответ 4
Причина того, что второй пример разрешен, но не первый, скорее всего, сохранит язык в порядке и не вводит странные правила.
Разрешить запуск любого кода до того, как супер был вызван, будет опасным, поскольку вы можете столкнуться с вещами, которые должны были быть инициализированы, но все еще не были. В принципе, я думаю, вы можете сделать довольно много вещей в вызове самому супер (например, вызвать статический метод для вычисления некоторого материала, который нужно перейти к конструктору), но вы никогда не сможете использовать что-либо из -ий-полностью построенный объект, что хорошо.
Ответ 5
То, как работает Java:-) Существуют технические причины, по которым он был выбран таким образом. Возможно, странно, что вы не можете выполнять вычисления на локальных компьютерах до вызова супер, но в Java сначала должен быть выделен объект и, следовательно, ему нужно пройти весь путь до объекта, чтобы все поля были правильно инициализированы до того, как вы сможете случайно модифицировать их.
В вашем случае чаще всего используется getter, который позволяет вам получить доступ к параметру, предоставленному super(). Поэтому вы должны использовать это:
super( new TextBox() );
final TextBox box = getWidget();
... do your thing...