在创建对象的同时在JAVA中执行静态块?

时间:2015-12-16 14:18:11

标签: java execution static-block

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()”,然后执行其他静态块。为什么呢?

3 个答案:

答案 0 :(得分:13)

所有类的静态初始化程序都已启动执行 - 但为了初始化D,必须初始化C,因此必须初始化B,因此必须初始化A。在执行A中的静态初始化程序中的代码时,所涉及的所有类都处于“正在初始化”状态。

A的静态初始值设定项中,它构造了C的实例 - 但C 已经已初始化,因此初始值设定项无法启动再次... JVM只是注意到它已经被初始化(在同一个线程内)并继续。

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

  

如果Class的{​​{1}}对象表示当前线程正在为C进行初始化,那么这必须是初始化的递归请求。发布C并正常完成。

  

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

     

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

......是相关的。

答案 1 :(得分:5)

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

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

现在,打开D房间的门需要打开C门,C需要B,B需要A.现在,你在A房,你在A房完成了开门手续。在A室完成开门手续时,你会看到完成C室工作的注释(A c=new C();)。现在,由于C室及其相关房间已经打开,您不需要再打开(意味着没有静态块初始化)。但是在你去C房之前,你将完成房间的开放手续,即System.out.println("Static A");所以,在控制台你有:

  

静态A

现在,你在C室,你必须完成这个房间,但在此之前你因为依赖而完成B和A(C扩展B和B扩展A)。所以,在控制台中你有:

  

Constr A.   建设B.   Constr C

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

  

静态B静态C静态D

现在,你正在完成D室(A a=new D();)的工作,为了做到这一点,你需要完成C,B和C的工作,因为依赖(D扩展C,C扩展B和B扩展A) 。所以,在控制台中你有:

  

Constr A Constr B Constr C Constr D

答案 2 :(得分:-2)

当jvm在那时开始运行时,将扫描所有静态成员并为他们分配内存然后它将不会静止..

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