25

我有 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");
     }
}

我创建了一个 Main 类,它只创建了新的 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实现中)?

是否建议一起避免使用静态初始化程序?

4

1 回答 1

25
static B b = new B();

是之前

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

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

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

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

请注意规范中的警告:

因为 Java 编程语言是多线程的,所以类或接口的初始化需要仔细同步,因为其他一些线程可能同时尝试初始化同一个类或接口。还有一种可能性是,作为该类或接口初始化的一部分,可以递归地请求类或接口的初始化;例如,类 A 中的变量初始化器可能调用不相关类 B 的方法,而后者又可能调用类 A的方法。Java 虚拟机的实现负责通过使用以下程序[文档继续完整程序]

在 Java 和其他语言中,最佳实践基本上是避免循环依赖,因为它们的解决方案可能很难预测。

于 2012-12-19T08:30:22.210 回答