本文介绍了为什么静态字段初始化失败导致NoClassDefFoundError?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个有趣的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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-19 12:48
查看更多