从非静态上下文调用相同 class 的 java 构造函数会导致递归,但是对于静态它可以正常工作吗?
calling a java constructor of same class from non static context leads to recursion but with static it works fine?
我想了解 Java class 的初始化顺序。具体什么时候以什么顺序是static和Instance initializer/fields执行的。我想出了这个 中的例子。为什么将静态添加到自构造函数调用会阻止代码进入递归。
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 Whosebug 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 - 当加载 class 并且初始化静态字段 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.WhosebugError
at Cons1.<init>(Cons1.java:33)
...
at Cons1.<init>(Cons1.java:33)
原因是 Cons1
的每个实例都需要另一个 Cons1
对象。所以我们溢出了调用堆栈,将 Cons1.<init>
方法推入其中。结果,当堆栈达到其最大允许大小时,我们以异常结束。
我想了解 Java class 的初始化顺序。具体什么时候以什么顺序是static和Instance initializer/fields执行的。我想出了这个
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 Whosebug 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 - 当加载 class 并且初始化静态字段 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.WhosebugError
at Cons1.<init>(Cons1.java:33)
...
at Cons1.<init>(Cons1.java:33)
原因是 Cons1
的每个实例都需要另一个 Cons1
对象。所以我们溢出了调用堆栈,将 Cons1.<init>
方法推入其中。结果,当堆栈达到其最大允许大小时,我们以异常结束。