Создание объекта класса в его собственном статическом инициализаторе

По JLS:

Класс или тип интерфейса T будет инициализирован непосредственно перед первое вхождение любого из следующего:

T - это класс и создается экземпляр T.

Также он говорит,

Инициализация класса состоит из выполнения его статического инициализаторы и инициализаторы для статических полей (переменные класса) объявленный в классе

Я выложу две точки из этого

  • Инициализация классов состоит из выполнения статических инициализаторов
  • Инициализация класса происходит, если класс создан.

Теперь,

Я предполагаю, что когда я создаю объект класса Test в своем собственном (Test own) статическом инициализаторе, он должен бросать мне переполнение стека, так как он должен вызывать себя повторно, потому что в соответствии с вышеприведенными двумя точками инициализация класса должна инициализироваться класс и блок инициализации имеют экземпляр класса. Переполнение стека происходит, когда я создаю экземпляр класса в своем собственном конструкторе или в его собственных инициализаторах экземпляра.

Например,

public class Test {

    static{
        System.out.println("static test");
        new Test();
    }
    {
       //new Test(); // This will give a stack overflow
        System.out.println("intializer");
    }

    public Test(){
        //new Test(); // This will give a stack overflow
        System.out.println("constructor");
    }
    public static void main(String[] args) {
    }

}

Однако результат - это нечто иное.

Результат:

статический тест

intializer Конструктор

Либо я слишком запутался в понимании инициализации класса, либо я извиняюсь, если мне не хватает чего-то очень очевидного здесь и ценю вашу помощь.

Ответы

Ответ 1

Шаг 3 процедуры инициализации класса, указанный в разделе JLS 12.4.2,

Если объект класса для C указывает, что инициализация выполняется для C текущим потоком, то это должно быть рекурсивным запросом на инициализацию. Отпустите LC и завершите работу нормально.

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

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

Ответ 2

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

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