Подтвердить что ты не робот

Какая разница между инициализатором экземпляра и конструктором?

Просто интересно узнать о причине компиляции кода следующим образом:

class MyClass extends AnotherClass {
  {
    MySecondClass object = new MySecondClass();
    object.doSomething();
  }
}

В чем разница между этим кодом и кодом в конструкторе? Этот код выполняет до создания объекта.

4b9b3361

Ответ 1

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

Быстрый пример:

public class Foo {
    {
        System.out.println("Before Foo()");
    }

    public Foo() {
        System.out.println("Inside Foo()");
    }

    {
        System.out.println("Not After Foo()");
    }
}

Ответ 2

Это называется инициализатором экземпляра. Код в инициализаторе вставляется после вызова конструктора суперкласса и перед остальным кодом конструктора.

Первая операция любого конструктора заключается в вызове конструктора суперкласса. Если конструктор явно вызывается, super(...), используется указанный конструктор. Если конструктор явно не вызывается, конструктор по умолчанию (без аргументов) вызывается в суперклассе. Если такой конструктор не существует, это ошибка времени компиляции.

После этого явного или неявного вызова конструктора инициализаторы экземпляра вызывают в порядке их появления в исходном коде (да, у вас может быть несколько инициализаторов).

Чтобы проиллюстрировать, запуск этой программы печатает

Another constructor
Init 1
Init 2
Test constructor
class Another {
  Another() { System.out.println("Another constructor"); }
}

class Test extends Another {

  public static void main(String[] args) { new Test(); }

  { System.out.println("Init 1"); }

  Test() { System.out.println("Test constructor"); }

  { System.out.println("Init 2"); }

}

Наиболее часто встречающееся приложение заключается в инициализации "идиомы двойной привязки" ,, где определен анонимный внутренний класс, и экземпляр создается и настраивается на один раз. Здесь довольно распространенный пример программирования Swing:

JButton popupButton = new JButton(new AbstractAction("Popup") {
  {
    putValue(Action.SHORT_DESCRIPTION, "Popup a dialog");
  }

  @Override
  public void actionPerformed(ActionEvent evt)
  {
    popup();
  }
});

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

Ответ 3

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

Просто интересно узнать о причине компиляции кода следующим образом:

Вы обычно используете его, чтобы разделить общий код при использовании перегрузки конструктора. Таким образом, "выше" на самом деле относится к одному из перегруженных конструкторов, который вызывается при создании объекта после выполнения кода кода инициализации общего экземпляра.

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