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

标签 java initialization static-initialization instance-initializers

我试图理解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).

JLS 10 - 8.3.1.1. static Fields

另一方面,

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.

JLS 10 - 8.3.2. Field Initialization

<小时/>

让我们添加一个 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/

相关文章:

java - 外部类中的静态初始化程序是否保证在内部枚举初始化之前运行?

c++ - 魔术静力学保证右侧只执行一次吗?

java - 使用 Mysql 数据库的搜索结果刷新 Jtable?

java - 我必须创建 Long 实例才能将 Long 作为参数发送吗?

c++ - 初始化文件良好实践

java - 用spring初始化和释放全局资源

java - 使用 Robolectric + Roboguice 时将日志输出写入哪里?

java - com.google.firebase.database.DatabaseException : Can't convert object of type java. lang.String 输入 com.harry.foodapp.Model.AdminOrders

java - 有效地根据属性 B 和 C 初始化属性 A

c++ - 对象构造/初始化的顺序