【问题标题】:When the static block will be executed in JAVA while creating object?什么时候在创建对象时在 JAVA 中执行静态块?
【发布时间】:2016-03-22 17:27:24
【问题描述】:
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 个类或可能只用 2 个类来证明这一点,并且同样容易 - 并且更容易提供完整的事件列表。

标签: java execution static-block


【解决方案1】:

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

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

所有这些的详细信息都在JLS 12.4.2 中。特别是项目符号:

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

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

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

... 是相关的。

【讨论】:

  • 我对“静态 B”之前的“Constr B”感到困惑。你有什么建议吗?
  • @Mikey:完全一样 - 它是构造 C 的一部分,发生在 A 的静态初始化程序的 body 正在执行时。
  • @Jon Skeet,你能帮我理解“..并正常完成”吗?答案中给出的 jls 引用中的短语。这是一个非常古老的线程,但不知何故我被困在试图理解
  • @MayankMadhav:“正常完成”意味着毫无例外地完成(相对于“突然完成”)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    @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();) 的工作,并且由于依赖关系,您需要完成 C、B 和 C 的工作(D 扩展 C、C 扩展 B 和 B 扩展 A)。所以,在控制台中你有:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-29
      • 1970-01-01
      • 2012-03-11
      • 2010-11-08
      • 1970-01-01
      • 2017-05-06
      • 2015-12-21
      • 2017-09-23
      相关资源
      最近更新 更多