在 Java 中运行构造函数代码之前是否初始化了字段?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14805547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are fields initialized before constructor code is run in Java?
提问by Praveen Kumar
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".
谁能解释以下程序的输出?我认为构造函数是在实例变量之前初始化的。所以我期待输出是“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();
}
}
回答by user207421
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().
- 静态变量初始化器和静态初始化块,按文本顺序,如果类之前没有被初始化。
- 构造函数中的 super() 调用,无论是显式还是隐式。
- 实例变量初始化器和实例初始化块,按文本顺序。
- super() 之后的剩余构造函数体。
See sections §2.17.5-6 of the Java Virtual Machine Specification.
请参阅Java 虚拟机规范的第2.17.5-6节。
回答by Arun P Johny
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
可以发现y
在构造函数内部移动了实例变量,所以执行顺序如下
- Call the constructor of
Z
- It triggers the default constructor of
X
- First line of
X
constructornew Y()
is called. - Print Y
- Print X
- Call the first line in constructor Z
new Y()
- Print
Y
- Print Z
- 调用构造函数
Z
- 它触发的默认构造函数
X
- 调用
X
构造函数的第一行new Y()
。 - 打印 Y
- 打印 X
- 调用构造函数 Z 中的第一行
new Y()
- 打印
Y
- 打印 Z
All the instance variables are initialized by using constructor statements.
所有实例变量都使用构造函数语句进行初始化。
回答by Vivek Pratap Singh
When you invoke a constructor, the instance variable initializers run before the body of the constructor.What do you think the output of the below program ?
当您调用构造函数时,实例变量初始值设定项在构造函数的主体之前运行。您认为以下程序的输出如何?
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");
}
}
}
The main method invokes the Tester constructor, which throws an exception. You might expect the catch clause to catch this exception and print Exception catched.
But if you tried running it, you
found that it does nothing of that sort and It throws a StackOverflowError
.
main 方法调用 Tester 构造函数,该构造函数引发异常。您可能期望 catch 子句捕获此异常并打印Exception catched。但是如果你尝试运行它,你会发现它什么都不做,它抛出一个StackOverflowError
.
回答by YoYo
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 aftertwo instance {}
. this happens because we throw in the constructor in the middle, interjecting execution order the first time the constructor is called.
请注意,我们有一个在两个实例之后static {}
调用的。发生这种情况是因为我们在中间插入了构造函数,在第一次调用构造函数时插入了执行顺序。{}
Discovered this when I was working on this answer - https://stackoverflow.com/a/30837385/744133.
在我处理这个答案时发现了这一点 - 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.
我需要研究继承的混合以及对 super 的显式和隐式调用将如何影响这一点,并将更新发现。它可能与其他提供的答案相似,只是它们在静态初始化时出错了。
回答by Abdul Razak
The initialization sequence is specified in JLS 12.5:
JLS 12.5 中指定了初始化顺序:
1.First, memory is allocated for the new object
1.首先为新对象分配内存
2.Then all instance variables in the object (including the ones defined in this class and all of its superclasses) are initialized to their default values
2.然后对象中的所有实例变量(包括在这个类及其所有超类中定义的)都被初始化为它们的默认值
3.Finally, the constructor is called.
3.最后调用构造函数。