我试图理解Java类的初始化顺序。具体来说,静态的时间和顺序以及实例初始值设定项/字段的执行时间。我想出了这样的例子 stackoverflow Question 。为什么将 static 添加到自构造函数调用中会阻止代码进入递归。
public class Test {
public static void main(String a[]) {
Cons1 c1 = new Cons1();
}
}
class Cons1 {
static Cons1 c = new Cons1(); /* if static is removed then recursion
occurs */
Cons1() {
//does something
}
}
静态上下文和实例上下文之间的行为差异是否有任何具体原因?我浏览了 Java 文档 Detailed Initialization Procedure ,但无法理解这种行为背后的逻辑是什么。对 JLS 规范的任何解释或引用都会有所帮助。
PS:我已经经历过这个Similar stackoverflow post ,但是我无法从那里得到答案。
最佳答案
If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized (§12.4).
另一方面,
<小时/>If the declarator is for an instance variable (that is, a field that is not static), then the following rules apply to its initializer:
- At runtime, the initializer is evaluated and the assignment performed each time an instance of the class is created.
让我们添加一个 println
声明查看全貌:
class Cons1 {
static Cons1 c = new Cons1();
Cons1() {
System.out.println("the constructor was called");
}
public static void main(String[] args) {
Cons1 c1 = new Cons1();
Cons1 c2 = new Cons1();
}
}
它输出“构造函数被调用”三次:
1 - 加载类和静态字段 c
时已初始化;
2 - 当 c1
已创建;
3 - 当 c2
已创建。
现在我们将其与带有实例字段的示例进行比较:
class Cons1 {
Cons1 c = new Cons1();
Cons1() {
System.out.println("the constructor was called");
}
public static void main(String[] args) {
Cons1 c1 = new Cons1();
}
}
显然,它失败了,下一个堆栈跟踪不打印任何内容:
Exception in thread "main" java.lang.StackOverflowError
at Cons1.<init>(Cons1.java:33)
...
at Cons1.<init>(Cons1.java:33)
原因是 Cons1
的每个实例需要另一个Cons1
目的。所以我们溢出调用堆栈推送 Cons1.<init>
里面的方法。结果,当堆栈达到允许的最大大小时,我们最终会遇到异常。
关于java - 从非静态上下文调用同一个类的java构造函数会导致递归,但是使用静态它可以正常工作吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49836528/