Почему статические поля не инициализируются во времени?

Следующий код печатает null один раз.

 class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); } public static void main(String[] args) {} } 

Почему статические объекты не инициализируются до запуска конструктора?

Обновить

Я просто скопировал эту примерную программу без внимания, я думал, что мы говорим о 2 полях Object, теперь я увидел, что первое поле MyClass ..: /

Поскольку статика инициализируется в порядке, указанном в исходном коде.

Проверь это:

 class MyClass { private static MyClass myClass = new MyClass(); private static MyClass myClass2 = new MyClass(); public MyClass() { System.out.println(myClass); System.out.println(myClass2); } } 

Это напечатает:

 null null myClassObject null 

РЕДАКТИРОВАТЬ

Хорошо, давайте сделаем это, чтобы быть более ясными.

  1. Статики инициализируются один за другим в порядке, указанном в исходном коде.
  2. Поскольку первый статический файл инициализируется перед остальными, во время его инициализации остальные статические поля имеют значение NULL или значение по умолчанию.
  3. Во время инициализации второго статического элемента первая статика правильна, а остальные по-прежнему равны нулю или по умолчанию.

Это ясно?

EDIT 2

Как указал Варман, ссылка на себя будет нулевой, пока она инициализируется. Что имеет смысл, если вы думаете об этом.

Попробуем по-другому объяснить это …

Это последовательность, с которой JVM проходит, когда вы впервые ссылаетесь на class MyClass .

  1. Загрузите байт-код в память.
  2. Память для статического хранилища очищается (двоичный ноль).
  3. Инициализировать class:
    1. Выполняйте каждый статический инициализатор в том порядке, в котором он появляется, включая статические переменные и static { ... } блоки static { ... } .
    2. Затем JVM инициализирует статическую переменную myClass в новом экземпляре MyClass .
    3. Когда это происходит, JVM замечает, что MyClass уже загружен (байт-код) и в процессе инициализации , поэтому он пропускает инициализацию.
    4. Выделите память на кучу для объекта.
    5. Выполнить конструктор.
    6. Распечатайте значение obj которое по-прежнему равно null (поскольку оно не является частью инициализированных переменных кучи и конструктора).
    7. Когда конструктор заканчивается, выполните следующий статический инициализатор, который устанавливает obj в новый экземпляр Object .
  4. Инициализация classа выполнена. С этого момента все вызовы конструктора будут вести себя так, как вы предполагаете / ожидаете – это obj не будет null а ссылкой на экземпляр Object .

Помните, что Java указывает, что final переменной присваивается значение один раз. Дело не в том, что гарантируется, что ему присваивается значение, когда код ссылается на него, если вы не убедитесь, что код ссылается на него после его назначения.

Это не ошибка. Это определенный способ обработки использования classа во время его собственной инициализации. Если бы это было не так, то JVM переходила бы в бесконечный цикл. См. Шаг № 3.3 (если JVM не пропускает инициализацию для classа, который находится в процессе инициализации, он просто сохранит его инициализацию – бесконечный цикл).

Обратите внимание, что все это происходит в том же streamе, который сначала ссылается на class. Во-вторых, JVM гарантирует, что инициализация завершится до того, как любой другой stream сможет использовать этот class.

Это потому, что Java выполняет статический раздел, чтобы он был объявлен. В вашем случае последовательность

  1. новый MyClass
  2. новый объект

Когда выполняется # 1, obj все еще не инициализируется, поэтому он печатает нуль. Попробуйте следующее, и вы увидите разницу:

 class MyClass { private static final Object obj = new Object(); private static MyClass myClass = new MyClass(); public MyClass() { System.out.println(obj); // will print null once } } 

Вообще говоря, лучше избегать такой конструкции все вместе. Если вы пытаетесь создать синглтон, вот как выглядит этот fragment кода:

 class MyClass { private static final MyClass myClass = new MyClass(); private Object obj = new Object(); private MyClass() { System.out.println(obj); // will print null once } } 

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

@Pyrolistical

поскольку начальный первый статический class myclass не полностью построен … результат, который я получаю, равен

null null [email protected] null

  • вызов нестатического метода в статическом методе в Java
  • статическая функция в C
  • Статические правила сериализации Java?
  • Почему все поля в интерфейсе неявно статичны и окончательны?
  • Статический инициализатор в Java
  • Что означает «статическое» значение в C?
  • Когда должен быть статический метод?
  • Java Static vs Instance
  • Порядок инициализации статических переменных
  • C # static member "inheritance" - почему это вообще существует?
  • Изменение частного статического конечного поля с использованием отражения Java
  • Interesting Posts
    Давайте будем гением компьютера.