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

2022-08-31 12:50:13

任何人都可以解释以下程序的输出吗?我认为构造函数是在实例变量之前初始化的。所以我期望输出是“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();
    }
}

答案 1

初始化的正确顺序是:

  1. 静态变量初始化器和静态初始化块,按文本顺序排列,如果类以前未初始化过。
  2. 构造函数中的 super() 调用,无论是显式的还是隐式的。
  3. 实例变量初始化器和实例初始化块,按文本顺序排列。
  4. 在 super() 之后构造函数的剩余主体。

请参阅 Java 虚拟机规范的 §2.17.5-6 节。


答案 2

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

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

  1. 调用 的构造函数Z
  2. 它触发默认构造函数X
  3. 调用构造函数的第一行。Xnew Y()
  4. 打印 Y
  5. 打印 X
  6. 调用构造函数 Z 中的第一行new Y()
  7. 打印Y
  8. 打印 Z

所有实例变量都使用构造函数语句进行初始化。