在使用Java运行构造函数代码之前是否初始化了字段?

Pra*_*mar 65 java constructor initialization

任何人都可以解释以下程序的输出吗?我认为构造函数在实例变量之前被初始化.所以我期待输出为"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();
    }
}
Run Code Online (Sandbox Code Playgroud)

use*_*421 95

正确的初始化顺序是:

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

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

  • Java 8 的 JLS 链接:http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 (3认同)

Aru*_*hny 57

如果你看一下类文件的反编译版本

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以发现实例变量y在构造函数中移动,因此执行顺序如下所示

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

使用构造函数语句初始化所有实例变量.

  • 实例变量的*initialization*在构造函数内移动. (2认同)

Viv*_*ngh 6

当您调用构造函数时,实例变量初始值设定项在构造函数主体之前运行。您认为以下程序的输出是什么?

public class Tester {
    private Tester internalInstance = new Tester();
    public Tester() throws Exception {
        throw new Exception("Boom");
    }
    public static void main(String[] args) {
        try {
            Tester b = new Tester();
            System.out.println("Eye-Opener!");
        } catch (Exception ex) {
            System.out.println("Exception catched");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

main 方法调用 Tester 构造函数,该构造函数抛出异常。您可能期望 catch 子句捕获此异常并打印Exception catched。但是,如果您尝试运行它,您会发现它没有执行任何此类操作,并且会抛出一个StackOverflowError.

  • 因此,您基本上试图表明构造函数将在控件到达 throw 部分之前继续调用自身(因为 private Tester internalInstance = new Tester(); 行)。我的理解正确吗? (2认同)