NoClassDefFoundError 与 ClassNotFoundException的区别
实验场景 1:
- 整体编译生成target目录及.class文件
- 删除com.wangfan.sign.consts.Const的.class文件
- 启动AoeTest.main
public class Const {
public static final Integer NM = 222222;
}
public class AoeTest {
public static void main(String[] args) {
try {
System.out.println(Const.NM);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
输出结果:
java.lang.NoClassDefFoundError: com/wangfan/consts/Const
at com.wfan.goldenTolwer.AoeTest.main(AoeTest.java:10)
Caused by: java.lang.ClassNotFoundException: com.wangfan.consts.Const
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
结论:
- NoClassDefFoundError是因为ClassNotFoundException导致
- ClassNotFoundException是因为运行时,通过classLoader加载此类的时候找不到com.wangfan.sign.consts.Const的.class文件。
实验场景 2:
- 整体编译生成target目录及.class文件
- 编写Const如下
- 启动AoeTest.main
public class Const {
public static final Integer SB = Integer.valueOf(null);
}
public class AoeTest {
public static void main(String[] args) {
try {
System.out.println(Const.SB);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println(Const.SB);
}
}
异常结果:
java.lang.ExceptionInInitializerError
at com.wfan.goldenTolwer.AoeTest.main(AoeTest.java:10)
Caused by: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:542)
at java.lang.Integer.valueOf(Integer.java:766)
at com.wangfan.consts.Const.<clinit>(Const.java:7)
... 1 more
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class com.wangfan.consts.Const
at com.wfan.goldenTolwer.AoeTest.main(AoeTest.java:14)
结论:
- 第一次System.out.println(Const.SB)的时候会因为初始化Const, 静态变量异常,ExceptionInInitializerError,所以初始化失败。
- 第二次System.out.println(Const.SB)的时候报NoClassDefFoundError,因为第一次初始化失败,导致Const类不可用。
总结:
- ClassNotFoundException可以发生在编译期,也可以发生在运行时。
- 发生在编译期,一般是由于编译出错,或者classpath错误。
- 发生在运行时,是ClassLoader动态加载类的时候找不到com.wangfan.sign.consts.Const的.class文件。如URLClassLoader.findClass
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
- NoClassDefFoundError是可以加载到.class文件,但是初始化类时,static变量或static块的异常,导致已经加载的类不可用。
参考
https://www.baeldung.com/java-classnotfoundexception-and-noclassdeffounderror
https://dzone.com/articles/java-classnotfoundexception-vs-noclassdeffounderro
https://my.oschina.net/jasonultimate/blog/166932
- ClassNotFoundException
ClassNotFoundException is a checked exception which occurs when an application tries to load a class through its fully-qualified name and can not find its definition on the classpath.
This occurs mainly when trying to load classes using Class.forName(), ClassLoader.loadClass() or ClassLoader.findSystemClass(). Therefore, we need to be extra careful of java.lang.ClassNotFoundException while working with reflection.
- NoClassDefFoundError
NoClassDefFoundError is a fatal error. It occurs when JVM can not find the definition of the class while trying to:
Instantiate a class by using the new keyword
Load a class with a method call
The error occurs when a compiler could successfully compile the class, but Java runtime could not locate the class file. It usually happens when there is an exception while executing a static block or initializing static fields of the class, so class initialization fails.
Let's consider a scenario which is one simple way to reproduce the issue. ClassWithInitErrors initialization throws an exception. So, when we try to create an object of ClassWithInitErrors, it throws ExceptionInInitializerError.