Порядок инициализации
Внутри класса порядок инициализации определяется порядком определения переменных класса. Определения переменных может быть разбросано внутри и между определений методов, но переменные инициализируются прежде, чем любой метод может быть вызван — даже конструктор. Например:
//: c04:OrderOfInitialization.java
// Демонстрация порядка инициализации.
// Когда конструктор вызывается для создания
// объекта Tag, вы увидите сообщение:
class Tag { Tag(int marker) { System.out.println("Tag(" + marker + ")"); } }
class Card { Tag t1 = new Tag(1); // Перед конструктором
Card() { // Указывает, что мы в конструкторе:
System.out.println("Card()"); t3 = new Tag(33); // Повторная инициализация t3
} Tag t2 = new Tag(2); // После конструктора
void f() { System.out.println("f()"); } Tag t3 = new Tag(3); // В конце
}
public class OrderOfInitialization { public static void main(String[] args) { Card t = new Card(); t.f(); // Показывает завершение конструктора
} } ///:~
В Card объекты Tag определяются вперемешку для обеспечения, чтобы они все были инициализированы до входа в конструктор и до того, как что-то еще случится. Кроме того, t3 повторно инициализируется внутри конструктора. На выходе получим:
Tag(1) Tag(2) Tag(3) Card() Tag(33) f()
Таким образом, ссылка t3 инициализируется дважды, один раз до входа в конструктор, а второй при вызове конструктора. (Первый объект выбрасывается, так что он может быть позже обработан сборщиком мусора.) Сначала это может показаться не эффективно, но это гарантирует правильную инициализацию — что могло бы произойти, если бы был определен перегруженный конструктор, который бы не инициализировал t3, и не было бы инициализации “по умолчанию” для t3 в точке определения?