7
class DemoClass {
    public static void main(String args[]) {
        System.out.println("Start");
        A a=new D();
    }
}
class A {
    static {
        System.out.println("Static A");
        A c=new C();
    }

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

class B extends A {
    static {
        System.out.println("Static B"); 
    }

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

class C extends B {
    static {
        System.out.println("Static C");
    }

    public C() {
        System.out.println("Constr C");
    }
}

class D extends C {
    static {
        System.out.println("Static D");
    }

    public D() {
        System.out.println("Constr D");
    }
}

上述代码的执行顺序为:

Start
Static A
Constr A
Constr B
Constr C
Static B
Static C
Static D
Constr A
Constr B
Constr C
Constr D

在我看来,应该首先执行所有静态块,然后只创建对象。但是,这里首先创建类 A 静态块中的对象“A c=new C()”,然后执行其他静态块。为什么?

4

3 回答 3

13

所有类的静态初始化器已经开始执行——但是为了初始化D,必须初始化C,所以必须初始化B,所以必须初始化A。在A执行静态初始化程序中的代码时,所涉及的所有类都处于“正在初始化”的状态。

在 的静态初始化程序中,它构造了一个- 但已经A初始化的实例,因此初始化程序不会再次启动...... JVM 只是注意到它已经被初始化(在同一个线程中)并继续。CC

所有这些的细节都在JLS 12.4.2中。特别是子弹:

如果Classfor 对象C指示当前线程正在对 C 进行初始化,那么这一定是对初始化的递归请求。释放LC并正常完成。

接下来,如果 C 是类而不是接口,并且它的超类尚未初始化,则令 SC 为其超类,并令 SI1,...,SIn 为声明至少一个默认方法的 C 的所有超接口。[...]

对于列表 [ SC, SI1, ..., SIn ] 中的每个 S,对 S 递归执行整个过程。如有必要,首先验证并准备 S。

...是相关的。

于 2015-12-16T14:22:58.277 回答
5

@JonSkeet 已经用技术术语说了一切,我不能说更多。让我试着用一个比喻来解释:

将静态初始化视为打开房间的门,将构造函数执行视为在该房间中做/完成事情。

现在,要打开D房间的门,你需要打开C的门,C需要B,B需要A。现在,你在A房间,你已经完成了A房间的开门手续。在完成门的同时在 A 室办理开业手续,您会看到 C 室已完成工作的纸条(A c=new C();)。现在由于房间 C 和它的附属房间已经打开,你不需要再打开(意味着没有静态块初始化)。但是在你去房间 C 之前,你将完成房间 A 的开放手续,即System.out.println("Static A");,在控制台中,你有:

静态A

现在,您在房间 C 中,您必须完成这个房间,但在此之前,由于依赖关系,您已经完成了 B 和 A(C 扩展了 B,B 扩展了 A)。所以,在控制台中你有:

约束 A 约束 B 约束 C

现在,您将再次回到A室,看到开门手续已完成。所以,你会来到房间 B,然后是 C,然后是 D。所以,在控制台中,你有:

静态 B 静态 C 静态 D

现在,您正在完成房间 D ( A a=new D();) 的工作,并且由于依赖关系(D 扩展 C,C 扩展 B 和 B 扩展 A),您需要完成 C、B 和 C 的工作。所以,在控制台中你有:

常数 A 常数 B 常数 C 常数 D

于 2015-12-16T14:38:51.090 回答
-2

当 jvm 启动时,所有静态成员都将被扫描并为它们分配内存,那么它将不使用静态 ..

所以首先它会打印静态然后非静态

于 2015-12-16T14:23:30.393 回答