Должен ли вызов конструктора super() быть самой первой строкой конструктора?

Должен ли вызов конструктора super() быть самой первой строкой конструктора? Если да, то почему? Почему я не могу сделать некоторые простые ограниченные вычисления перед вызовом конструктора, например, вычисление параметров конструктора?

Я обнаружил ситуацию с конструкторами внутренних классов, которые можно вызывать с указанием замыкания:

class A {
    class Inner1 {
        Inner1() {
            // do something
        }
    }
}

class B {
    A a1 = new A();
    A a2 = new A();

    class Inner2 extends A.Inner1 {
         Inner2(boolean sel) {
             (sel?a1:a2).super();
         }
    }

}

Этот случай показывает, что мы можем захотеть выбрать объемлющий экземпляр для конструктора базового класса. Почему логика выбора должна быть такой ограниченной? Почему нельзя написать что-то подобное

if( sel ) {  
    a1.super();
}
else {
    a2.super();
}

ДОПОЛНЕНИЕ

Под моим вопросом я подразумеваю, что ограничение может быть как в следующем случае:

public class Base {

private final String content;

public Base(String content) {
    this.content = content;
}

public String getContent() {
    return content;
}

}


public class Derived extends Base {

public Derived(String content) {
    super(String.format("Current value of content is %s.", getContent()));
}


}

В последнем случае я:

1) Выполнение требования super() быть в первой строке

2) Нарушение порядка строительства

3) Получите ошибку компилятора «Невозможно ссылаться на метод экземпляра при явном вызове конструктора»

Итак, почему мы не можем отменить «требование первой строки» и полагаться только на такие ошибки, как последняя?


person Suzan Cioc    schedule 23.05.2012    source источник
comment
super() должен быть помещен в первую строку вызова конструктора, если вы его используете, но проверьте этот поток: stackoverflow.com/questions/9675431/ или это: stackoverflow.com/questions/1168345/   -  person wkl    schedule 24.05.2012
comment
Спасибо! Обходные пути интересны, но также интересно, почему Java была сделана такой, т.е. что плохого, если я сделаю что-то перед вызовом super? Например, меня можно было бы просто обязать не обращаться к членам экземпляра, пока не вызову super.   -  person Suzan Cioc    schedule 24.05.2012
comment
@SuzanCioc Если вы сделаете что-то до звонка super(). Java остановит вашу программу и предложит вам исправить ее.   -  person Hunter McMillen    schedule 24.05.2012
comment
@Suzan Cioc, вторая ссылка, предоставленная birryree, охватывает этот вопрос.   -  person dantuch    schedule 24.05.2012
comment
@Suzan Существуют языки (python), которые позволяют вызывать конструктор суперкласса позже или вообще не вызывать. Это, очевидно, может иметь плохие последствия, но ведь мы все знаем, что вызов super() первым не решает всех проблем и создает множество новых. Однако это упрощение, потому что это означает, что нам не нужно разделять выделение объектов и инициализацию на две отдельные части. И я предполагаю, что это позволяет избежать одного вида проблем, которые в противном случае возникали бы регулярно.   -  person Voo    schedule 24.05.2012
comment
Пожалуйста, посмотрите мое дополнение. Я не хочу иметь дело с неинициализированными экземплярами, как в C++, мне просто интересно, почему мы не можем полагаться на такие проверки, как Cannot ссылаться на метод экземпляра при явном вызове конструктора?   -  person Suzan Cioc    schedule 24.05.2012


Ответы (2)


Да, вызов super() требуется как самый первый вызов в конструкторе.

Настолько, что если вы пропустите это, компилятор (попытается) вставить вызов для вас. Чтобы понять почему, вам нужно понять философию разработчиков Java. Гослинг всегда принадлежал к лагерю ученых-компьютерщиков, которые считают, что доступ к частично инициализированным объектам — один из главных источников ошибок в компьютерных программах. И поэтому он разработал строгую иерархию инициализации, которая помогла бы решить эту проблему. Если вы согласны с философией, это спорно, но важно понимать, что это такая же важная концепция в Java, как, например, ссылки против указателей или реальные ограниченные массивы. Следует отметить, что даже такие языки, как Objective C, которые позволяют вам вызывать инициализацию в любое время, делают все возможное, чтобы обеспечить цепочку инициализации, за исключением того, что они должны делать это по соглашению, а не строго. правила языка.

Я не уверен, что вы пытались проиллюстрировать в своем примере, но после многих лет разработки с Java я сомневаюсь, что вы найдете много случаев, когда вам действительно нужно выполнить логику перед вызовом super.

person Perception    schedule 23.05.2012

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

person ejb_guy    schedule 23.05.2012
comment
Но какая принципиальная разница, если я напишу одно длинное, но одно выражение с super() и если я напишу многострочный код? - person Suzan Cioc; 24.05.2012
comment
можете пожалуйста объяснить. В основном, если конструктор класса Object не выполняется, у вас нет объекта для работы. И чтобы убедиться, что вызывается конструктор объекта, вызов super() должен быть первой строкой - person ejb_guy; 24.05.2012
comment
посмотрите на мой вопрос, пожалуйста. Я предоставил два кода расширенного конструктора, которые идентичны по логике, но только первый из них разрешен Java. - person Suzan Cioc; 24.05.2012