ext*_*xt2 34 java static initialization noclassdeffounderror
这是一个有趣的java问题.
以下简单的java程序包含静态方法初始化的静态字段.实际上,我强制计算intiailize值的方法引发NullPointException,当我访问这样的静态字段时,会引发NoClassDefFoundError.似乎VM对待Class并不完整.
但是当我访问Class时,它仍然可用;
有谁知道为什么?
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
tru*_*ity 34
这些问题的答案通常都隐藏在规范的某个地方...... (§12.4.2)
初始化类时会发生什么:
步骤1-4与此问题有些无关.这里的第5步是触发异常的原因:
5.如果Class对象处于错误状态,则无法进行初始化.释放Class对象上的锁并抛出NoClassDefFoundError.
6-8继续初始化,8执行初始化器,通常发生的是在步骤9:
9.如果初始化程序的执行正常完成,则锁定此Class对象,将其标记为完全初始化,通知所有等待的线程,释放锁定,并正常完成此过程.
但是我们在初始化程序中出错了所以:
10.否则,初始化器必须通过抛出一些异常E而突然完成.如果E的类不是Error或其子类之一,则创建一个新的ExceptionInInitializerError类实例,以E作为参数,并使用此对象在下一步中的E.但是,如果由于发生OutOfMemoryError而无法创建新的ExceptionInInitializerError实例,则在以下步骤中使用OutOfMemoryError对象代替E.
是的,我们看到ExceptionInInitializerError空指针异常的b/c.
11.锁定Class对象,将其标记为错误,通知所有等待的线程,释放锁定,并在原因E或其替换中突然完成此过程,如上一步骤所确定.(由于某些早期实现中的缺陷,忽略了类初始化期间的异常,而不是如此处所述导致ExceptionInInitializerError.)
然后该类被标记为错误,这就是我们第二次从第5步获得异常的原因.
令人惊讶的部分是第三打印输出,其示出了
TestClass.class在MainClass实际持有到物理的参考Class对象.
可能因为TestClass仍然存在,它只是标记为错误.它已经加载并验证.
irr*_*ble 14
是的,这通常是为什么NoClassDefFoundError被提出来的.这是邪恶的名字,就是这样.它应该被命名为"类init失败异常"或其他东西.
由于误导性的名称,得到这个错误的java程序员浪费了数百年的时间来试图弄清楚为什么无法找到这个类.
每当您看到此异常时,您应该向上检查日志,并尝试在类无法初始化时找出根本原因.
| 归档时间: |
|
| 查看次数: |
20290 次 |
| 最近记录: |