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

Следующий код печатает 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..:/

Ответ 1

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

Проверьте это:

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

ИЗМЕНИТЬ

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

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

Это ясно?

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

  • новый MyClass
  • новый объект

Когда выполняется # 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
  }
}

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

class MyClass {

  private static final MyClass myClass = new MyClass();

  private Object obj = new Object();

  private MyClass() {
    System.out.println(obj); // will print null once
  }
}

Ответ 4

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

Ответ 5

@Pyrolistical

так как исходный первый статический класс myclass не полностью построен... результат я получается

нулевой ноль [email protected] нуль