Java类初始化的相互引用和次序问题
simpleman7210
2013-10-16
JVM书上一般都会说,类或接口在首次主动使用的时候要初始化,就是执行类或接口的<clinit>方法。一个类如果有父类,初始化它之前应该先初始化其父类。这些说法都不难理解。但是考虑一些相互引用的类,有可能陷入一种循环之中,比如下面一个例子。
class class1 { static int _x1; static { _x1 = class2._x2; } } class class2 extends class1 { static int _x2; static { _x2 = 20; //_x2 = class1._x1; } } class TestClassInit { public static void main(String[] args) { System.out.println(class2._x2); } } 在这个例子中,main()访问class2的静态变量,这导致要初始化class2,而class2继承自class1,因此class1要先初始化。在class1的初始化代码中,访问了class2的静态变量,一般这要求初始化class2。那么要不要执行class2的初始化呢?显然我们看出,这是不可以的,因为这样做就陷入了初始化循环。 把上面的例子稍微改一下: class class1 { static int _x1; static { _x1 = class4._x4; } } class class2 extends class1 { static int _x2; static { _x2 = 20; //_x2 = class1._x1; } } class class3 extends class1 { static int _x3; static { _x3 = 30; } } class class4 extends class3 { static int _x4; static { _x4 = 40; } } class TestClassInit { public static void main(String[] args) { System.out.println(class2._x2); } } 这个例子中,class1的初始化代码中,引用class4,我们看class4继承自class3,而class3继承自class1。那么在执行class4的初始化代码中,要不要初始化class4呢(进而初始化class3)?如果执行class4的初始化,那么就执行到class3的初始化,class3的初始化又面对要执行class1的初始化。 由此问题就出来了:要如何处理类的初始化次序,尤其在初始化过程中潜在的循环初始化问题? |
|
RednaxelaFX
2013-10-16
规范里有讲。我之前在这帖里引用过对应部分的规范,请参考:http://hllvm.group.iteye.com/group/topic/37682
|
|
simpleman7210
2013-10-16
我之前也看过规范的这部分,我以为规范没有细致回答我的问题。现在看来,可能是规范中论述初始化的第3点,回答了我的问题:
3. 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. 这段意思说,如果发现要初始化的类,正处在初始化过程中,那么就算完成了。也就是说,不再尝试再一次初始化这个类。从而避免了循环。 在我前面的第一个例子中,class1访问class2的静态变量,导致要初始化class2,但准备初始化class2的时候,发现class2正处在初始化过程中,因此,不再初始化class2。 在第二个例子中,class1访问class4的静态变量,导致要初始化class4。class4没有被初始化,也不在初始化过程中,因此,class4将被初始化。初始化class4时,因为继承自class3,class3也没有被初始化或在初始化过程中,因此class3将被初始化,class3继承自class1,而class1正处在初始化过程中,因此class3的初始化,仅仅是class3自己的初始化,不再初始化class1了。 |
|
RednaxelaFX
2013-10-16
simpleman7210 写道 我之前也看过规范的这部分,我以为规范没有细致回答我的问题。现在看来,可能是规范中论述初始化的第3点,回答了我的问题:
3. 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. 正解了。 |