递归初始化:当我访问Class字段时,不会调用静态初始化程序

时间:2015-05-09 16:52:16

标签: java static classloader

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

In what order do static initializer blocks

所以,我只是想确认一下 -

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 个答案:

答案 0 :(得分:1)

访问OOMErrorB.c时,OOMErrorB 未加载,因为它已经处于加载过程中(当JVM最初加载它时,为了调用{{ 1}}方法)。在JVM中加载类后,将不再加载它。因此,不会发生循环依赖:main的静态成员OOMErrorB被提取,此时仍未初始化。

您可以查看关于类初始化的this section from the Java language specification

  

由于Java编程语言是多线程的,因此初始化类或接口需要仔细同步,因为其他一些线程可能正在尝试同时初始化同一个类或接口。 作为该类或接口的初始化的一部分,还可以递归地请求类或接口的初始化;例如,类A中的变量初始化程序可能会调用不相关的类B的方法,而该方法又可能调用类A的方法。通过使用该方法,Java虚拟机的实现负责处理同步和递归初始化。以下程序。

JVM有正确的方法来锁定类的初始化,以防止递归初始化。