静态初始化程序在构造函数之后运行,为什么?

Avi*_*gal 24 java constructor static-initialization

我有2个班:

A类:

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

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

     public A() {
         System.out.println("A constructor");
     }
}
Run Code Online (Sandbox Code Playgroud)

B级:

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

     public B() {
         System.out.println("B constructor");
     }
}
Run Code Online (Sandbox Code Playgroud)

我创建一个Main类,它只创建新的A:

public class Main {
    public static void main(String[] args) {
        new A();
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

B static block
A constructor
B constructor
A static block
A constructor
Run Code Online (Sandbox Code Playgroud)

如您所见,A的构造函数在其静态初始化程序之前被调用.

我理解它与我创建的循环依赖有关,但我的印象是静态初始化器应该始终在构造函数之前运行.

发生这种情况的原因是什么(技术上在java实现中)?

是否建议一起避免静态初始化器?

Den*_*ret 24

static B b = new B();
Run Code Online (Sandbox Code Playgroud)

在此之前

static {
     System.out.println("A static block");
}
Run Code Online (Sandbox Code Playgroud)

因此,您需要在打印之前初始化B实例"A static block".

初始化B类意味着您需要创建一个A实例.因此,在构造A实例之前,无法打印"静态块".

是的,A的静态初始化是在构造函数启动之前启动的,但除了死锁之外,没有其他解决方案可用于您需要的序列.

请注意规范中的警告:

由于Java编程语言是多线程的,因此初始化类或接口需要仔细同步,因为某些其他线程可能正在尝试同时初始化相同的类或接口.作为该类或接口的初始化的一部分,还可以递归地请求类或接口的初始化; 例如,类A中的变量初始化程序可能会调用不相关的类B的方法,而该方法又可能调用类A方法.通过使用该方法, Java虚拟机的实现负责处理同步和递归初始化.以下程序[文件继续完整程序]

Java中的最佳实践与其他语言一样,基本上是为了避免循环依赖,因为它们的分辨率可能很难预测.