gpt4 book ai didi

java - JVM递归类初始化实现

转载 作者:行者123 更新时间:2023-12-04 08:43:01 25 4
gpt4 key购买 nike

我正在研究 JVM 规范/内部结构,并想了解循环引用的递归类初始化应该如何正确发生。看这个例子:

 class CA extends Object {
public final int ivar = 1;
public static CB other = new CB();
public CA() {
System.out.println("in CA.init, my ivar is " + this.ivar);
}
}
class CB extends Object {
public final int ivar = 2;
public static CA other = new CA();
public CB() {
System.out.println("in CB.init, my ivar is " + this.ivar);
}

public static void main(String[] args) {
CB cb = new CB();
}
}
执行这个结果:
in CB.init, my svar is 2
in CA.init, my ivar is 1
in CB.init, my svar is 2
这些反射(reflect)了实例初始化并且有意义。类 inits 必须像这样运行:
  • CB <clinit>实例化一个 CA,它应该触发...
  • CA <clinit> ,它实例化一个 CB,它尝试一个
  • CB <clinit>再次,这已经在进行中...

  • JVM 规范在 s5.5 初始化下说:
    1. If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.

    这意味着在我上面的第 3 步中,JVM 耸了耸肩,然后返回完成第 2 步。但完成第 2 步意味着调用构造函数 <init>在新的 CB 实例上。当 CB 类还没有完成它的 <clinit> 时,它怎么能做到这一点? ?
    在这种情况下,因为对象没有对它们持有的彼此实例“做任何事情”,所以没有伤害没有犯规。但是我应该如何考虑这里的行为和潜在的陷阱?谢谢。

    最佳答案

    这只有效,因为这些是静态字段( other ),如果您删除该修饰符 - 您将获得 StackOverflow (因为例如字段,初始化移动到构造函数)。在我看来,如果我向您展示编译器实际在做什么,事情可能会变得很明显?

    static class CA extends Object {

    public final int ivar = 1;
    public static CB other;

    static {
    System.out.println("running CA static block");
    other = new CB();
    System.out.println("CB done");
    }

    public CA() {
    System.out.println("in CA.init, my ivar is " + ivar);
    }
    }

    static class CB extends Object {

    public final int ivar = 2;
    public static CA other;

    static {
    System.out.println("running CB static block");
    other = new CA();
    System.out.println("CA done");
    }

    public CB() {
    System.out.println("in CB.init, my ivar is " + ivar);
    }


    }
    编辑
    搞乱调用什么实例方法,直到类完全初始化确实很危险。您可能会遇到意想不到的事情:
     static class CB {

    private static final CB ONLY = new CB();

    private static final Integer IVAR = 42;
    public final int ivar = IVAR;

    }

    public static void main(String[] args) {
    System.out.println(CB.ONLY.ivar);
    }
    这会抛出一个 NullPointerException .为什么?您可以自己反编译并查看,但用相当简单的话说:
  • ivar通过读取 IVAR 在构造函数中初始化多变的
  • 静态按它们在代码中出现的顺序执行

  • 所以,首先 private static final CB ONLY = new CB();执行,因此,必须调用构造函数,因此 ivar初始化。 ivar设置为 IVAR ,但后者只有在构造函数完成后才会被初始化。所以当试图设置 ivar ,它将取消装箱 IVAR 的值,此时(因为 CB 未完全初始化)是 null .

    关于java - JVM递归类初始化实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64470359/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com