在Java中运行构造函数代码之前,字段是否已初始化?

任何人都可以解释下面的程序的输出吗? 我认为构造函数在实例变量之前被初始化。 所以我期待输出是“XZYY”。

class X {
    Y b = new Y();

    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class Z extends X {
    Y y = new Y();

    Z() {
        System.out.print("Z");
    }

    public static void main(String[] args) {
        new Z();
    }
}

正确的初始化顺序是:

  • 如果该类先前未被初始化,则按照文本顺序的静态变量初始化程序和静态初始化块。
  • 构造函数中的super()调用,无论是显式还是隐式。
  • 实例变量初始化程序和实例初始化块,按照文本顺序。
  • super()之后剩余的构造函数体。
  • 请参阅Java虚拟机规范的§2.17.5-6部分。


    如果您查看类文件的反编译版本

    class X {
        Y b;
    
        X() {
            b = new Y();
            System.out.print("X");
        }
    }
    
    class Y {
        Y() {
            System.out.print("Y");
        }
    }
    
    public class Z extends X {
    
        Y y;
    
        Z() {
            y = new Y();
            System.out.print("Z");
        }
    
        public static void main(String args[]) {
            new Z();
        }
    }
    

    你可以发现实例变量y被移入构造函数内部,所以执行顺序如下

  • 调用Z的构造函数
  • 它触发X的默认构造函数
  • X构造函数new Y()第一行被调用。
  • 打印Y
  • 打印X
  • 调用构造函数Z new Y()的第一行
  • 打印Y
  • 打印Z
  • 所有实例变量都使用构造函数语句进行初始化。


    为了澄清静态的误解 - 我将简单地引用这一小段代码:

    public class Foo {
      { System.out.println("Instance Block 1"); }
      static { System.out.println("Static Block 1"); }
      public static final Foo FOO = new Foo();
      { System.out.println("Instance Block 2"); }
      static { System.out.println("Static Block 2 (Weird!!)"); }
      public Foo() { System.out.println("Constructor"); }
      static public void main(String p[]) {
        System.out.println("In Main");
        new Foo();
      }
    }
    

    惊喜是输出如下:

    Static Block 1
    Instance Block 1
    Instance Block 2
    Constructor
    Static Block 2 (Weird!!)
    In Main
    Instance Block 1
    Instance Block 2
    Constructor
    

    请注意,我们有一个在两个实例{}之后调用的static {} {} 。 发生这种情况是因为我们在中间引入构造函数,在第一次调用构造函数时插入执行顺序。

    当我正在处理这个答案时发现了这个问题 - https://stackoverflow.com/a/30837385/744133。

    基本上我们观察到这会发生:

  • 在第一次初始化对象时,根据发生的顺序混合静态和实例初始化的当前对象

  • 对于所有下一次初始化,只能按发生顺序进行实例初始化,因为已经发生了静态初始化。

  • 我需要研究继承的组合,以及对super和this的显式和隐式调用都会对此产生影响,并会随调查结果进行更新。 它可能类似于其他提供的答案,除了它们在静态初始化时出错。

    链接地址: http://www.djcxy.com/p/20593.html

    上一篇: Are fields initialized before constructor code is run in Java?

    下一篇: PHP random string generator