«Немногие программисты знают о том, что конструкторы и методы класса могут выполняться до его инициализации» - PullRequest
18 голосов
/ 17 ноября 2011

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

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

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

Ответы [ 3 ]

29 голосов
/ 17 ноября 2011

В основном они говорят о следующей ситуации:

public class Foo {
    public static Foo INSTANCE = new Foo(); // Prints null

    public static String s = "bar";

    public Foo() {
        System.out.println(s);
    }
}

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

Это не то, что вы часто видите в своей повседневной работе, но вы должны знать об этой возможности и избегать ее при написании кода.

5 голосов
/ 17 ноября 2011

В качестве примера рассмотрим отправку виртуального метода в конструкторе.

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 находится в состоянии.

0 голосов
/ 17 ноября 2011

Я думаю, что они имеют в виду логическую инициализацию.Например, в вашем классе A есть метод init(), который необходимо вызвать перед использованием любых бизнес-методов.Но другой программист, который использует этот класс, не читал руководство и написал new A().foo().Вероятно, в этом случае foo() не может работать правильно.В этом случае утверждение может быть полезным.В начале вы можете проверить, что init() не был вызван, и выбросить утверждение.

То же самое с конструкторами.Это может произойти, когда кто-то продлит ваш класс A:

class B extends A {
    B() {
        foo(); // init() must be called before foo!
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...