Are fields initialized before constructor code is run in Java?

Can anyone explain the output of following program? I thought constructors are initialized before instance variables. So I was expecting the output to be "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();
    }
}

The correct order of initialisation is:

  • Static variable initialisers and static initialisation blocks, in textual order, if the class hasn't been previously initialised.
  • The super() call in the constructor, whether explicit or implicit.
  • Instance variable initialisers and instance initialisation blocks, in textual order.
  • Remaining body of constructor after super().
  • See sections §2.17.5-6 of the Java Virtual Machine Specification.


    If you look at the decompiled version of the class file

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

    You can find that the instance variable y is moved inside the constructor, so the execution sequence is as follows

  • Call the constructor of Z
  • It triggers the default constructor of X
  • First line of X constructor new Y() is called.
  • Print Y
  • Print X
  • Call the first line in constructor Z new Y()
  • Print Y
  • Print Z
  • All the instance variables are initialized by using constructor statements.


    To clarify the misconceptions with static - I will simply refer to this small piece of code:

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

    Surprise is that the output is as follows:

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

    Note that we have a static {} that is called after two instance {} . this happens because we throw in the constructor in the middle, interjecting execution order the first time the constructor is called.

    Discovered this when I was working on this answer - https://stackoverflow.com/a/30837385/744133.

    Basically we observe this to happen:

  • During the first time an object is initialized, Initialize current object for both static and instance initialization intermixed based on order of occurrence

  • For all next initializations, only do the instance initialization in the order of occurrence, as static initialization already happened.

  • I need to research how the mix of inheritance, and both explicit and implicit calls to super and this will affect this, and will update with findings. It would be likely similar to the other supplied answers, except that they got it wrong with the static initialization.

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

    上一篇: 在控制台上打印消息而不使用main()方法

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