问题描述
这是一个有趣的java问题.
Here is a interesting java question.
以下简单的java程序包含由静态方法初始化的静态字段.实际上,我强制计算初始化值的方法引发 NullPointException,当我访问这样的静态字段时,将引发 NoClassDefFoundError.看来VM 对待Class 是不完整的.
the following simple java program contains static field initialized by a method statically. Actually, I force the method which calculate the intiailize value to raise a NullPointException, When I access such a static field, a NoClassDefFoundError will raised. it seems the VM treat the Class is not complete.
但是当我访问该类时,它仍然可用;
But when I access the Class, it still available;
有人知道为什么吗?
class TestClass {
public static TestClass instance = init();
public static TestClass init() {
String a = null;
a.charAt(0); //force a null point exception;
return new TestClass();
}
}
class MainClass {
static public void main(String[] args) {
accessStatic(); // a ExceptionInInitializerError raised cause by NullPointer
accessStatic(); //now a NoClassDefFoundError occurs;
// But the class of TestClass is still available; why?
System.out.println("TestClass.class=" + TestClass.class);
}
static void accessStatic() {
TestClass a;
try {
a = TestClass.instance;
} catch(Throwable e) {
e.printStackTrace();
}
}
}
推荐答案
这些问题的答案通常隐藏在规范的某个地方... (§12.4.2)
The answer to such questions is usually buried somewhere in the specs... (§12.4.2)
初始化类时会发生什么:
What happens when classes are initialized:
步骤 1-4 与此问题有些无关.第 5 步是触发异常的原因:
Steps 1-4 are somewhat unrelated to this question. Step 5 here is what triggers the exception:
5
.如果 Class 对象处于错误状态,则无法进行初始化.释放对 Class 对象的锁定并抛出 NoClassDefFoundError.
6-8 继续初始化,8 执行初始化器,通常发生在第 9 步:
6-8 continue the initialization, 8 executes the initializers, and what usually happens is in step 9:
9
.如果初始化器的执行正常完成,则锁定这个Class对象,标记它完全初始化,通知所有等待的线程,释放锁,正常完成这个过程.
但是我们在初始化程序中遇到了错误,因此:
But we got an error in the initializer so:
10
.否则,初始化程序必须通过抛出一些异常 E 突然完成.如果 E 的类不是 Error 或其子类之一,则 创建类 ExceptionInInitializerError 的新实例,使用 E作为参数, 并在接下来的步骤中使用此对象代替 E.但是,如果由于发生 OutOfMemoryError 而无法创建 ExceptionInInitializerError 的新实例,则在以下步骤中使用 OutOfMemoryError 对象代替 E.
是的,我们看到了空指针异常的 ExceptionInInitializerError
b/c.
Yep, we see an ExceptionInInitializerError
b/c of the null pointer exception.
11
.锁定 Class 对象,将其标记为错误,通知所有等待的线程,释放锁定,并在上一步中确定的原因 E 或其替换的情况下突然完成此过程.(由于一些早期实现中的缺陷,类初始化期间的异常被忽略,而不是像这里描述的那样导致 ExceptionInInitializerError.)
然后该类被标记为错误,这就是我们第二次从第 5 步中得到异常的原因.
And then the class is marked erroneous which is why we get the exception from step 5 the second time.
令人惊讶的部分是第三个打印输出,它显示 MainClass
中的 TestClass.class
实际上持有对物理 Class
对象的引用.
可能是因为 TestClass
仍然存在,它只是被标记为错误.已加载并验证.
Probably because TestClass
still exists, it's just marked erroneous. It has been already loaded and verified.
这篇关于为什么静态字段初始化失败导致NoClassDefFoundError?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!