"Немногие программисты знают о том, что конструкторы классов и методы могут запускаться до его инициализации"
В официальном руководстве Java Программирование с утверждениями указано, что
(последний абзац на странице)
Немногие программисты знают о том, что конструкторы классов и методы могут запускаться до его инициализации. Когда это произойдет, вполне вероятно, что инварианты класса еще не установлены, что может вызвать серьезные и тонкие ошибки.
Что подразумевается под этим? Когда это происходит? Это то, о чем я должен заботиться в своем ежедневном использовании Java?
Ответы
Ответ 1
В основном, они говорят о следующей ситуации:
public class Foo {
public static Foo INSTANCE = new Foo(); // Prints null
public static String s = "bar";
public Foo() {
System.out.println(s);
}
}
Как вы можете видеть, в этом случае конструктор запускается перед инициализатором статического поля s
, i. е. до полной инициализации класса. Это просто простой пример, но он может усложняться, когда задействованы несколько классов.
Это не то, что вы часто можете увидеть в своей повседневной работе, но вам нужно знать об этой возможности и избегать ее при написании кода.
Ответ 2
В качестве примера рассмотрим отправку виртуального метода в конструкторе.
class Foo {
Foo() {
int a = bar();
b = 7;
}
private int b;
protected int baz() { assert b == 7; return b; } ;
protected abstract int bar();
}
Если подкласс произошел с вызовом baz
из их реализации bar
, они попали бы в это утверждение. Объект не завершил построение, поэтому базовый класс Foo
находится в состоянии бит.
Ответ 3
Я думаю, что они означают логическую инициализацию. Например, ваш класс A имеет метод init()
, который должен быть вызван перед использованием любых бизнес-методов. Но другой программист, который использует этот класс, не читал руководства и написал new A().foo()
. Вероятно, в этом случае foo()
работает неправильно. В этом случае утверждение может быть полезным. Вы можете проверить в начале, что init()
не был вызван и не выдает утверждение.
То же самое с конструкторами. Это может произойти, когда кто-то расширяет ваш класс A:
class B extends A {
B() {
foo(); // init() must be called before foo!
}
}