为什么java中的实例initiazer块只执行一次?

为什么java中的实例initiazer块只执行一次?,java,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 { {

输出

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();
    }
}
根据,

Java编译器将初始值设定项块复制到每个构造函数中。 因此,这种方法可用于在用户之间共享代码块 多个构造函数。”


那么,为什么类B的初始值设定项块不执行两次,而构造函数执行两次呢?

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

那么,为什么类B的初始值设定项块不会像构造函数执行两次一样执行两次呢

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

一般来说,您不需要费心推理实例初始值设定项代码的确切复制位置。只需依赖于这样一个事实,即它将为每个对象初始化运行一次,并且只运行一次

实例初始值设定项运行的时刻是在完成
super()
构造函数调用之后


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

如果您对教程中阅读的内容有疑问,请尝试在Java语言规范或JDK Javadoc中找到权威性语句

 IIB B
Cons B int
Cons B
 IIB C
Cons C
下面是为上述类生成的字节码:

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");
    }
}
公共类com.foo.Initializer{
public com.foo.Initializer();
代码:
0:aload_0
1:iconst_0
2:调用特殊的#1//方法“”:(Z)V
5:getstatic#2//fieldjava/lang/System.out:Ljava/io/PrintStream;
8:ldc#3//无参数构造函数中的字符串
10:invokevirtual#4//方法java/io/PrintStream.println:(Ljava/lang/String;)V
13:返回
公共com.foo.Initializer(布尔);
代码:
0:aload_0
1:invokespecial#5//方法java/lang/Object。“:()V
4:getstatic#2//fieldjava/lang/System.out:Ljava/io/PrintStream;
7:ldc#6//初始值设定项中的字符串
9:invokevirtual#4//方法java/io/PrintStream.println:(Ljava/lang/String;)V
12:getstatic#2//Field java/lang/System.out:Ljava/io/PrintStream;
15:ldc#7//布尔构造函数中的字符串
17:invokevirtual#4//方法java/io/PrintStream.println:(Ljava/lang/String;)V
20:返回
}

您可以看到,初始值设定项块实际上并没有复制到所有构造函数。它只在布尔构造函数中复制,因为编译器检测到无参数构造函数委托给布尔构造函数。因此,本教程中的句子简化了实际发生的情况。

那么您希望执行多少次?初始化过程在universe中的任何创建过程中只执行一次。有关Java中对象初始化的更详细概述,请参阅。因此,“Java编译器将初始化程序块复制到每个构造函数中”的语句为false???您是否可以添加指向此规范的链接?
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        
}