Java中的NoClassDefFoundError

时间:2020-01-09 10:34:59  来源:igfitidea点击:

在本文中,我们将讨论java.lang.NoClassDefFoundError及其修复方法。

Java中何时引发NoClassDefFoundError

当在编译时存在类时,在Java中出现NoClassDefFoundError,但是在运行时,JVM或者ClassLoader实例尝试在类的定义中加载时,找不到该类。

请注意,NoClassDefFoundError是java.lang.Error的后代。由于它属于错误类型,因此我们无法执行任何异常处理来从中恢复。

NoClassDefFoundError Java示例

假设我有一个程序可以将文件读取到使用commons-io的commons.io.FileUtils的字节数组中,xxx.jar包含在类路径中。程序可以毫无问题地编译和执行。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

public class FileToByteArray {
  public static void main(String[] args) {
    File file = new File("F:\theitroad\links.txt");        
    readToByteArrayUsingCommons(file);  
  }
	
  private static void readToByteArrayUsingCommons(File file){
    try(FileInputStream fis = new FileInputStream(file)) {
      byte[] bArray = IOUtils.toByteArray(fis);
      for (int i = 0; i < bArray.length; i++){
        System.out.print((char) bArray[i]);
      }
      bArray = FileUtils.readFileToByteArray(file);
      for (int i = 0; i < bArray.length; i++){
        System.out.print((char) bArray[i]);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

现在,我们将代码类移动到另一台服务器,但是以某种方式错过了所需的jar commons-io-xxx.jar。然后,我们将收到此错误,因为现在在运行时所需的IOUtils类不存在。

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/io/IOUtils
        at com.theitroad.programs.FileToByteArray.readToByteArrayUsingCommons(FileToByteArray.java:18)
        at com.theitroad.programs.FileToByteArray.main(FileToByteArray.java:13)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.io.IOUtils
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 2 more

从堆栈跟踪中可以看到,由于ClassNotFoundException而引发了NoClassDefFoundError。 NoClassDefFoundError的另一个原因是ExceptionInInitializerError,当在评估静态初始值设定项或者静态变量的初始值设定项期间发生异常时。

在下面的示例中,有一个带有静态块的ABC类,该类将由于被零除而引发异常。在主要方法中,创建了ABC类的两个实例。第一次初始化尝试将引发ExceptionInInitializerError,而第二次尝试将导致NoClassDefFoundError,因为JVM已经知道无法创建ABC类的实例。

public class NoClassDef {

  public static void main(String[] args) {
    try {
      ABC obj1 = new ABC();
    }catch (Throwable e) {
      e.printStackTrace();
    }
    System.out.println("in here");
    // Trying to initialize again
    ABC obj2 = new ABC();
  }
}

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

输出:

java.lang.ExceptionInInitializerError
	at com.theitroad.programs.NoClassDef.main(NoClassDef.java:7)
Caused by: java.lang.ArithmeticException: / by zero
	at com.theitroad.programs.ABC.(NoClassDef.java:18)
	... 1 more
in here
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class com.theitroad.programs.ABC
	at com.theitroad.programs.NoClassDef.main(NoClassDef.java:12)

解决NoClassDefFoundError时,我们必须寻找根本原因,最终导致抛出NoClassDefFoundError。