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

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

У меня есть 2 класса:

Класс A:

public class A {
    static B b = new B();

     static {
         System.out.println("A static block");
     }

     public A() {
         System.out.println("A constructor");
     }
}

Класс B:

public class B {
     static {
         System.out.println("B static block");
         new A();
     }

     public B() {
         System.out.println("B constructor");
     }
}

Я создаю Основной класс, который просто создает новый A:

public class Main {
    public static void main(String[] args) {
        new A();
    }
}

Выход, который я получаю:

B static block
A constructor
B constructor
A static block
A constructor

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

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

В чем причина этого (технически в реализации Java)?

Рекомендуется ли избегать статических инициализаторов вместе?

4b9b3361

Ответ 1

static B b = new B();

до

static {
     System.out.println("A static block");
}

Итак, вам нужно, чтобы экземпляр B был инициализирован перед печатью "A static block".

И инициализация класса B означает, что вам нужно создать экземпляр A. Таким образом, нет возможности для того, чтобы "Статический блок" был напечатан до создания экземпляра A.

Да, статическая инициализация A запущена до запуска конструктора, но, помимо взаимоблокировки, не будет другого решения для требуемой последовательности.

Обратите внимание на предупреждение в спецификацию:

Поскольку язык программирования Java многопоточен, инициализация класса или интерфейса требует тщательной синхронизации, поскольку некоторые другой поток может пытаться инициализировать тот же класс или интерфейс в то же время. Существует также возможность инициализации класс или интерфейс могут быть запрошены рекурсивно как часть инициализация этого класса или интерфейса; например, переменная инициализатор в классе A может ссылаться на метод несвязанного класса B, которые, в свою очередь, могут вызвать метод класса A.. виртуальная машина Java отвечает за соблюдение синхронизации и рекурсивной инициализации с использованием следующих процедура [документ продолжается с полной процедурой]

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