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

"Немногие программисты знают о том, что конструкторы классов и методы могут запускаться до его инициализации"

В официальном руководстве Java Программирование с утверждениями указано, что (последний абзац на странице)

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

Что подразумевается под этим? Когда это происходит? Это то, о чем я должен заботиться в своем ежедневном использовании Java?

4b9b3361

Ответ 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!
    }
}