JVM规范在提及NoClassDefFoundError说到了2处:
(1)
q 如果C的Class对象显示它处于一个错误的状态,就不再初始化了。释放LC并抛出NoClassDefFoundError异常。
意思是说C初始化失败了,那么第二次就直接抛出这个异常NoClassDefFoundError
如Truman提供的例子(我稍加改编如下):
for(int i = 0; i <2 ; i ++){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Caller.test();
} catch (Throwable e) {
System.out.println("_____________________");
e.printStackTrace();
}
java.lang.ExceptionInInitializerError-第一次初始化失败
at com.cisco.webex.Test.main(Test.java:14)
Caused by: java.lang.RuntimeException: throw exception in constructor.
at com.cisco.webex.PramterA.<init>(PramterA.java:6)
at com.cisco.webex.Caller.<clinit>(Caller.java:12)
... 1 more
_____________________第二次初始化直接报NoClassDefFoundError
java.lang.NoClassDefFoundError: Could not initialize class com.cisco.webex.Caller
at com.cisco.webex.Test.main(Test.java:14)
(2)
如果Java虚拟机曾经试图在D(调用者)的验证(§5.4.1)或解析(§5.4.3)阶段、但又还没有进行初始化(§5.5)时加载C类,当用于加载C的初始类加载器抛出ClassNotFoundException实例时,Java虚拟机在D中必须抛出NoClassDefFoundError异常,它的cause字段中就保存了那个ClassNotFoundException异常实例。
例如:
public class Invoker {
public static final Object fileService = new ExternalGek4();
public Invoker() {
}
}
假设我在编译后,运行前删除ExternalGek4,然后运行new Invoker(),这个时候会抛出NoClassDefFoundError, 当然cause是(ClassNotFoundException)。
这个和JAVADOC里面说的很匹配:
* Thrown if the Java Virtual Machine or a <code>ClassLoader</code> instance
* tries to load in the definition of a class (as part of a normal method call
* or as part of creating a new instance using the <code>new</code> expression)
* and no definition of the class could be found.
* <p>
* The searched-for class definition existed when the currently
* executing class was compiled, but the definition can no longer be
* found.
编译在,运行时不在了。
总结:
NoClassDefFoundError 这种错误应该有2个原因可能导致:
(1) 第一次初始化对象失败,第二次时报错。
(2) 类真的找不到
特征前者是第一次初始化中有错, 后者是含有 class not found(CLASS PATH等问题)的CAUSE
那么根绝相应的LOG就可以简单判断是那种错误。然后有针对性的处理。
Ps 与CLASSNOTFOUND的区别:
CLASSNOTFOUND有可能包装成NoClassDefFoundError
NoClassDefFoundError可以不由classnotfoundexception引起。