Конструктор
родительского класса должен быть вызван перед конструктором подкласса
. Это гарантирует, что если вы вызовете какие-либо методы родительского класса в своем конструкторе, родительский класс уже будет правильно настроен.
То, что вы пытаетесь сделать, передать аргументы в суперконструктор совершенно законно, вам просто нужно чтобы построить эти аргументы встроенными, как вы это делаете, или передать их вашему конструктору, а затем передать их в super
:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
super(myArray);
}
}
Если компилятор не принудил к этому, вы можете сделать это:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
someMethodOnSuper(); //ERROR super not yet constructed
super(myArray);
}
}
В случаях где родительский класс
имеет конструктор по умолчанию, вызов super вставляется автоматически компилятором
. Поскольку каждый класс в Java наследуется от объекта
, Конструктор объектов нужно как-то вызывать и запускать первым. Автоматическая вставка super () компилятором позволяет это. Принуждение к появлению super первым приводит к тому, что тела конструктора выполняются в правильном порядке: Объект -> Родитель -> Дочерний -> ChildOfChild -> SoOnSoForth
Вы можете использовать блоки анонимного инициализатора для инициализации полей в дочернем элементе перед вызовом его конструктора. Этот пример демонстрирует:
public class Test {
public static void main(String[] args) {
new Child();
}
}
class Parent {
public Parent() {
System.out.println("In parent");
}
}
class Child extends Parent {
{
System.out.println("In initializer");
}
public Child() {
super();
System.out.println("In child");
}
}
Это выведет:
В родительском
В инициализаторе
In child
Я почти уверен (те, кто знаком со спецификацией Java, вмешивается), что это предотвращает (а) использование частично сконструированного объекта и (б) принудительное использование родительского объекта конструктор класса для построения на "свежий "объект.
Вот некоторые примеры" плохого ":
class Thing
{
final int x;
Thing(int x) { this.x = x; }
}
class Bad1 extends Thing
{
final int z;
Bad1(int x, int y)
{
this.z = this.x + this.y; // WHOOPS! x hasn't been set yet
super(x);
}
}
class Bad2 extends Thing
{
final int y;
Bad2(int x, int y)
{
this.x = 33;
this.y = y;
super(x); // WHOOPS! x is supposed to be final
}
}
Потому что так говорит JLS. Можно ли изменить JLS совместимым образом, чтобы разрешить это? Ага.
Однако это усложнило бы спецификацию языка, которая и так уже более чем достаточно сложна. Это было бы не очень полезно, и есть способы обойти это (вызовите другой конструктор с результатом статического метода или лямбда-выражения this (fn ())
- метод вызывается перед другой конструктор, а значит, и суперконструктор). Таким образом, соотношение мощности и веса выполнения изменения неблагоприятно.
Обратите внимание, что это правило само по себе не предотвращает использование полей до того, как суперкласс завершит построение.
Рассмотрим эти недопустимые примеры.
super(this.x = 5);
super(this.fn());
super(fn());
super(x);
super(this instanceof SubClass);
// this.getClass() would be /really/ useful sometimes.
Этот пример является допустимым. , но "неверно".
class MyBase {
MyBase() {
fn();
}
abstract void fn();
}
class MyDerived extends MyBase {
void fn() {
// ???
}
}
В приведенном выше примере, если MyDerived. fn
требовал аргументов от конструктора MyDerived
, которые нужно было бы обработать с помощью ThreadLocal
. ; (
Между прочим, начиная с Java 1.4, синтетическое поле, содержащее внешний this
, назначается перед вызовом суперконструктора внутренних классов. Это вызвало странные события NullPointerException
в коде, скомпилированном для нацелены на более ранние версии.
Обратите также внимание на то, что при наличии небезопасной публикации конструкция может просматриваться в другом порядке, если не приняты меры предосторожности.
Редактировать март 2018 г .: В сообщении Записи: строительство и проверка Oracle предлагает снять это ограничение (но в отличие от C #, этот
будет определенно неназначенным (DU) перед объединением конструкторов).
Исторически сложилось так, что this () или super () должны быть первыми в конструкторе. Эта ограничение никогда не было популярным и воспринималось как произвольное. Были ряд тонких причин, в том числе проверка invokespecial, который способствовал этому ограничению. С годами мы обратились к ним на уровне ВМ, до такой степени, что становится целесообразно рассмотреть снятие этого ограничения, не только для записей, но для всех конструкторов.