为什么java中的实例初始化块只执行一次?

时间:2014-02-28 08:58:09

标签: java

class B {

    {
        System.out.println("IIB B");
    }

    B(int i) {
        System.out.println("Cons B int");

    }

    public B() {
        this(10);
        System.out.println("Cons B");
    }
}

public class C extends B {

    {
        System.out.println("IIB C");
    }

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

    public static void main(String[] args) {
        C c1 = new C();
    }
}

输出

 IIB B
Cons B int
Cons B
 IIB C
Cons C

根据Oracle tutorials

  

“Java编译器将初始化程序块复制到每个构造函数中。   因此,这种方法可用于共享一段代码   多个构造函数。“

那么为什么B类的初始化程序块没有执行两次,因为构造函数执行了两次?

3 个答案:

答案 0 :(得分:7)

  

那么为什么B类的初始化程序块没有执行两次,因为构造函数执行了两次?

不,构造函数只运行一次。编译器会考虑将工作委托给另一个构造函数,并且实例初始值设定项不会复制到以this()调用开头的构造函数中。

通常,您无需担心复制实例初始化程序代码的确切位置。简单地说,它将为每个对象初始化运行一次

实例初始化程序运行的时刻是在完成super()构造函数调用后立即执行的。


术语

您在问题中包含的链接不是Javadocs,而是Oracle Tutorial。这两者之间有一个非常重要的区别:Javadocs是规范,而教程只是描述性。教程中的一些措辞可能不精确,作为教学价值与事实准确性之间的折衷。

如果您对教程中读过的内容有疑问,请尝试在Java语言规范或JDK Javadoc中查找权威声明。

答案 1 :(得分:4)

您只创建了B的一个实例。 C的一个实例。因此,它只会打印一次,因为构造函数只运行一次。尝试创建C的另一个实例,然后您将打印两次。

答案 2 :(得分:2)

public class Initializer {
    {
        System.out.println("in initializer");
    }

    public Initializer() {
        this(false);
        System.out.println("in no-arg constructor");
    }

    public Initializer(boolean b) {
        System.out.println("in boolean constructor");
    }
}

这是为上述类生成的字节码:

public class com.foo.Initializer {
  public com.foo.Initializer();
    Code:
       0: aload_0       
       1: iconst_0      
       2: invokespecial #1                  // Method "<init>":(Z)V
       5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: ldc           #3                  // String in no-arg constructor
      10: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      13: return        

  public com.foo.Initializer(boolean);
    Code:
       0: aload_0       
       1: invokespecial #5                  // Method java/lang/Object."<init>":()V
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: ldc           #6                  // String in initializer
       9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #7                  // String in boolean constructor
      17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return        
}

您会看到初始化程序块实际上并未复制到所有构造函数。它仅在布尔构造函数中复制,因为编译器检测到no-arg构造函数委托给布尔构造函数。因此,本教程中的句子简化了实际发生的事情。