admin管理员组

文章数量:1031883

ClassNotFoundException与NoClassDefFoundError分析

1. 简介

当 JVM 在类路径上找不到请求的类时,就会发生 ClassNotFoundExceptionNoClassDefFoundError。虽然它们看起来很熟悉,但这两者之间存在一些核心差异。

在本教程中,我们将讨论它们发生的一些原因及其解决方案。

2. 类未找到异常

ClassNotFoundException 是一个经过检查的异常,当应用程序尝试通过其完全限定名加载类并且无法在类路径上找到其定义时,就会发生该异常。

这主要发生在尝试使用 Class.forName()、ClassLoader.loadClass() 或 ClassLoader.findSystemClass() 加载类时。因此,在使用反射时,我们需要格外小心java.lang.ClassNotFoundException

例如,让我们尝试加载 JDBC 驱动程序类,而不添加必要的依赖项,这将获得 ClassNotFoundException:

代码语言:javascript代码运行次数:0运行复制
@Test(expected = ClassNotFoundException.class)
public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() 
  throws ClassNotFoundException {
      Class.forName("oracle.jdbc.driver.OracleDriver");
}

3. NoClassDefFoundError

NoClassDefFoundError 是一个致命错误。当 JVM 在尝试执行以下操作时找不到类的定义时,就会发生这种情况:

  • 使用 new 关键字实例化类
  • 使用方法调用加载类

当编译器可以成功编译类,但 Java 运行时找不到类文件时,会发生此错误。它通常发生在执行静态块或初始化类的静态字段时出现异常,因此类初始化失败。

让我们考虑一个场景,这是重现问题的一种简单方法。ClassWithInitErrors 初始化引发异常。因此,当我们尝试创建 ClassWithInitErrors 的对象时,它会抛出 ExceptionInInitializerError。

如果我们尝试再次加载相同的类,我们会得到 NoClassDefFoundError:

代码语言:javascript代码运行次数:0运行复制
public class ClassWithInitErrors {
    static int data = 1 / 0;
}
代码语言:javascript代码运行次数:0运行复制
public class NoClassDefFoundErrorExample {
    public ClassWithInitErrors getClassWithInitErrors() {
        ClassWithInitErrors test;
        try {
            test = new ClassWithInitErrors();
        } catch (Throwable t) {
            System.out.println(t);
        }
        test = new ClassWithInitErrors();
        return test;
    }
}

让我们为此场景编写一个测试用例:

代码语言:javascript代码运行次数:0运行复制
@Test(expected = NoClassDefFoundError.class)
public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() {
 
    NoClassDefFoundErrorExample sample
     = new NoClassDefFoundErrorExample();
    sample.getClassWithInitErrors();
}

4. 解决

有时,诊断和修复这两个问题可能非常耗时。这两个问题的主要原因是类文件(在类路径中)在运行时不可用。

让我们看一下在处理其中任何一个时我们可以考虑的几种方法:

  1. 我们需要确保包含该类的类或 jar 在类路径中是否可用。如果没有,我们需要添加它
  2. 如果它在应用程序的类路径上可用,则很可能类路径被覆盖。为了解决这个问题,我们需要找到应用程序使用的确切类路径
  3. 此外,如果应用程序使用多个类装入器,那么由一个类装入器装入的类可能不被其他类装入器提供。为了很好地排除故障,必须了解类加载器在 Java 中的工作方式

5. 总结

虽然这两个异常都与类路径和 Java 运行时在运行时找不到类有关,但重要的是要注意它们的差异。

Java 运行时仅在尝试在运行时加载类时抛出 ClassNotFoundException,并且名称是在运行时提供的。在 NoClassDefFoundError 的情况下,该类在编译时存在,但 Java 运行时在运行时无法在 Java 类路径中找到它。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2023-04-07,如有侵权请联系 cloudcommunity@tencent 删除javaclassnotfoundexceptionnoclassdeffounderror编译异常

ClassNotFoundException与NoClassDefFoundError分析

1. 简介

当 JVM 在类路径上找不到请求的类时,就会发生 ClassNotFoundExceptionNoClassDefFoundError。虽然它们看起来很熟悉,但这两者之间存在一些核心差异。

在本教程中,我们将讨论它们发生的一些原因及其解决方案。

2. 类未找到异常

ClassNotFoundException 是一个经过检查的异常,当应用程序尝试通过其完全限定名加载类并且无法在类路径上找到其定义时,就会发生该异常。

这主要发生在尝试使用 Class.forName()、ClassLoader.loadClass() 或 ClassLoader.findSystemClass() 加载类时。因此,在使用反射时,我们需要格外小心java.lang.ClassNotFoundException

例如,让我们尝试加载 JDBC 驱动程序类,而不添加必要的依赖项,这将获得 ClassNotFoundException:

代码语言:javascript代码运行次数:0运行复制
@Test(expected = ClassNotFoundException.class)
public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() 
  throws ClassNotFoundException {
      Class.forName("oracle.jdbc.driver.OracleDriver");
}

3. NoClassDefFoundError

NoClassDefFoundError 是一个致命错误。当 JVM 在尝试执行以下操作时找不到类的定义时,就会发生这种情况:

  • 使用 new 关键字实例化类
  • 使用方法调用加载类

当编译器可以成功编译类,但 Java 运行时找不到类文件时,会发生此错误。它通常发生在执行静态块或初始化类的静态字段时出现异常,因此类初始化失败。

让我们考虑一个场景,这是重现问题的一种简单方法。ClassWithInitErrors 初始化引发异常。因此,当我们尝试创建 ClassWithInitErrors 的对象时,它会抛出 ExceptionInInitializerError。

如果我们尝试再次加载相同的类,我们会得到 NoClassDefFoundError:

代码语言:javascript代码运行次数:0运行复制
public class ClassWithInitErrors {
    static int data = 1 / 0;
}
代码语言:javascript代码运行次数:0运行复制
public class NoClassDefFoundErrorExample {
    public ClassWithInitErrors getClassWithInitErrors() {
        ClassWithInitErrors test;
        try {
            test = new ClassWithInitErrors();
        } catch (Throwable t) {
            System.out.println(t);
        }
        test = new ClassWithInitErrors();
        return test;
    }
}

让我们为此场景编写一个测试用例:

代码语言:javascript代码运行次数:0运行复制
@Test(expected = NoClassDefFoundError.class)
public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() {
 
    NoClassDefFoundErrorExample sample
     = new NoClassDefFoundErrorExample();
    sample.getClassWithInitErrors();
}

4. 解决

有时,诊断和修复这两个问题可能非常耗时。这两个问题的主要原因是类文件(在类路径中)在运行时不可用。

让我们看一下在处理其中任何一个时我们可以考虑的几种方法:

  1. 我们需要确保包含该类的类或 jar 在类路径中是否可用。如果没有,我们需要添加它
  2. 如果它在应用程序的类路径上可用,则很可能类路径被覆盖。为了解决这个问题,我们需要找到应用程序使用的确切类路径
  3. 此外,如果应用程序使用多个类装入器,那么由一个类装入器装入的类可能不被其他类装入器提供。为了很好地排除故障,必须了解类加载器在 Java 中的工作方式

5. 总结

虽然这两个异常都与类路径和 Java 运行时在运行时找不到类有关,但重要的是要注意它们的差异。

Java 运行时仅在尝试在运行时加载类时抛出 ClassNotFoundException,并且名称是在运行时提供的。在 NoClassDefFoundError 的情况下,该类在编译时存在,但 Java 运行时在运行时无法在 Java 类路径中找到它。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2023-04-07,如有侵权请联系 cloudcommunity@tencent 删除javaclassnotfoundexceptionnoclassdeffounderror编译异常

本文标签: ClassNotFoundException与NoClassDefFoundError分析