ClassNotFoundException vs. NoClassDefFoundError

Published: Creative Commons Licence

  • Tags:

概述

二者产生的原因都是在运行时找不到需要的类,但ClassNotFoundException是一种Checked Exception,NoClassDefFoundError是一种Error。

Exception和Error的区别:
二者都是Throwable的子类,只有Throwable才能被throw和catch。
Exception是程序运行过程中,可以预料的意外情况,应该被捕获,进行相应的处理。
Error是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序自身(比如JVM)处于非正常的、不可恢复状态,所以不便于也不需要捕获。

ClassNotFoundException

当应用程序尝试通过诸如 Class.forName() 的方式来加载类,但是无法在Classpath下找到对应的类时,就会抛出ClassNotFoundException。eg:

try {
    Class<?> c = Class.forName(className);
} catch (ClassNotFoundException e) {
    System.out.println("No such class: " + className);
}

通常情况下,这都是由于没有导入需要的jar包导致的。比如在使用jdbc连接数据库时使用的:Class.forName("oracle.jdbc.driver.OracleDriver"); 如果不注意引入jar包就会抛出ClassNotFoundException。

NoClassDefFoundError

当一个类可以在编译期找到,却无法在运行期找到时,JVM就会抛出NoClassDefFoundError。

一种可能性是编译后的class文件遭到了篡改,导致运行时找不到需要的类。比如:

public class NoClassDefFoundErrorTest {
    public static void main(String[] args) {
        Foo foo = new Foo();
  }
}
class Foo {
}

在上面的类编译完成(javac NoClassDefFoundErrorTest.java)之后,去编译输出目录人工删除Foo.class文件,然后再直接运行(java com.sunshinevvv.thinkinginjava.typeinfo.NoClassDefFoundErrorTest),就会抛错:

Exception in thread "main" java.lang.NoClassDefFoundError: com/sunshinevvv/thinkinginjava/typeinfo/Foo
        at com.sunshinevvv.thinkinginjava.typeinfo.NoClassDefFoundErrorTest.main(NoClassDefFoundErrorTest.java:6)
Caused by: java.lang.ClassNotFoundException: com.sunshinevvv.thinkinginjava.typeinfo.Foo
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more

注意到这里的 Caused by: java.lang.ClassNotFoundException: com.sunshinevvv.thinkinginjava.typeinfo.Foo,可见NoClassDefFoundError和ClassNotFoundException还是有一定的关联的。

另外,如果一个类在初始化时出错了,也会抛出 NoClassDefFoundError。比如:

public class NoClassDefFoundErrorTest {
    public static void main(String[] args) {
        InitErrorClass initErrorClass = new InitErrorClass();
    }
}

class InitErrorClass {
    static {
        int i = 1 / 0;
    }
}

会抛错:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at com.sunshinevvv.thinkinginjava.typeinfo.NoClassDefFoundErrorTest.main(NoClassDefFoundErrorTest.java:9)
Caused by: java.lang.ArithmeticException: / by zero
        at com.sunshinevvv.thinkinginjava.typeinfo.InitErrorClass.<clinit>(NoClassDefFoundErrorTest.java:15)
        ... 1 more

参考资料

  • http://www.baeldung.com/java-classnotfoundexception-and-noclassdeffounderror
  • https://dzone.com/articles/java-classnotfoundexception-vs-noclassdeffounderro