递归初始化:访问类字段时静态初始化器没有被调用

3

了解加载类和调用静态初始化程序

静态初始化程序块的顺序是什么

因此,我试图确认一下 -

public class OOMErrorB extends OOMErrorA {
    public static int c = 10;

    static {
        System.out.println("Loading static B " + c);
        System.out.println(OOMErrorA.a);
    }

    public static void main(String[] args) {
        new OOMErrorB();
    }
}

父类是 -
public class OOMErrorA {
    public static int a = 20;

    static {
        a = a+ OOMErrorB.c;
        System.out.println("OOMErrorB.c " + OOMErrorB.c);
        System.out.println("loading OOMErrorA.a " + a);
    }
}

现在是B类的主方法输出 -
OOMErrorB.c 0
loading OOMErrorA.a 20
Loading static B 10
20

我可以理解,首先加载A类,因为它是超类,并调用其静态初始化程序,

现在,由于在OOMErrorA的静态块中访问OOMErrorB.c,因此它应该加载并调用OOMErrorB的静态初始化程序。 因此,OOMErrorB.c应该是10而不是0。

我对类的加载和初始化的了解-

1) Class and gets loaded and variables are initialized to default values like for int - 0, Object - null.
2) Class field are initialized to specified values.
3) Static block gets called .

在我的程序中,我可以看到 OOMErrorB 类被加载了(步骤1),但步骤2和步骤3没有执行。
而根据链接中被接受的答案,它应该调用 OOMErrorB 的静态初始化程序。
所以它应该最终陷入循环依赖关系?
1个回答

1
访问 OOMErrorB.c 时,由于 JVM 最初加载它以调用 main 方法,因此不会加载 OOMErrorB(当时已经在加载中)。一旦类在 JVM 中加载,就不会再次加载。因此,没有发生循环依赖:获取 OOMErrorB 的静态成员 c,此时仍未初始化。您可以查看 Java 语言规范中的此部分 了解类初始化的详细信息。
因为Java编程语言是多线程的,类或接口的初始化需要仔细同步,因为可能有其他线程正在尝试同时初始化相同的类或接口。此外,作为该类或接口初始化的一部分,还有可能递归请求类或接口的初始化;例如,类A中的变量初始化器可能会调用无关类B的方法,而类B可能反过来调用类A的方法。Java虚拟机的实现负责通过以下过程处理同步和递归初始化。
JVM有自己的方式锁定类的初始化,以防止递归初始化。

程序还没有进入主方法,我们可以在那里打印一个语句来查看。 - Adon Smith
哦,我想我明白了,所以JVM会按照以下步骤工作- 1)它将加载A类(步骤1) 2)然后它将加载B类(步骤1)3)它将调用A类的静态方法4)它将调用B类的静态方法。 - Adon Smith
@AdonSmith 你说得对。我的意思是在JVM调用其main方法之前就已经加载了它。 - M A
你同意我提到的步骤吗? - Adon Smith
@AdonSmith 具体步骤也在提供的链接中提到。请参阅https://dev59.com/WGIk5IYBdhLWcg3wr_5o。 - M A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接