繁体   English   中英

从非静态上下文中调用同一类的Java构造函数会导致递归,但使用静态,它可以正常工作吗?

[英]calling a java constructor of same class from non static context leads to recursion but with static it works fine?

我试图了解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文档的详细初始化过程 ,但是无法理解这种行为背后的逻辑是什么。 对JLS规范的任何解释或参考将很有帮助。

PS:我已经看过这个类似stackoverflow的帖子 ,但是我无法从那里得到答案。

如果将一个字段声明为static ,则无论该类最终会创建多少实例(可能为零), 都只存在该字段的一种形式 在初始化类时(第12.4节),将实现一个静态字段(有时称为类变量)。

JLS 10-8.3.1.1。 静态场

另一方面,

如果声明符用于实例变量 (即非静态字段),则以下规则适用于其初始化程序:

  • 在运行时, 每次创建该类的实例时,都会评估初始化器并执行分配。

JLS 10-8.3.2。 现场初始化


让我们添加一个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();
    }
}

显然,它失败,并且下一个stacktrace不输出任何内容:

Exception in thread "main" java.lang.StackOverflowError
    at Cons1.<init>(Cons1.java:33)
    ...
    at Cons1.<init>(Cons1.java:33)

原因是Cons1每个实例Cons1需要另一个Cons1对象。 因此,我们在调用栈中溢出了Cons1.<init>方法。 结果,当堆栈达到其最大允许大小时,我们最终会遇到异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM