ChatGPT解决这个技术问题 Extra ChatGPT

NoClassDefFoundError 和 ClassNotFoundException 之间的原因和区别是什么?

NoClassDefFoundErrorClassNotFoundException 有什么区别?

是什么导致它们被抛出?如何解决?

在修改现有代码以包含新的 jar 文件时,我经常会遇到这些 throwable。对于通过 webstart 分发的 java 应用程序,我已经在客户端和服务器端点击了它们。

我遇到的可能原因:

未包含在 build.xml 中的包对于我们正在使用的新 jar 的代码运行时类路径的客户端缺少与以前的 jar 版本冲突

当我今天遇到这些时,我会采取一种试错的方法来让事情顺利进行。我需要更多的清晰和理解。

我经常发现使用 -verbose(例如 -verbose:class -verbose:jni)运行 JVM 会有所帮助 - 但 mogsie 在他们的回答下方报告说,这没有提供额外有用的信息 :(

c
coobird

与 Java API 规范的区别如下。

对于 ClassNotFoundException

当应用程序尝试通过其字符串名称加载类时抛出:类 Class 中的 forName 方法。 ClassLoader 类中的 findSystemClass 方法。 ClassLoader 类中的 loadClass 方法。但找不到具有指定名称的类的定义。

对于 NoClassDefFoundError

如果 Java 虚拟机或 ClassLoader 实例尝试加载类的定义(作为正常方法调用的一部分或作为使用 new 表达式创建新实例的一部分)并且找不到类的定义,则抛出此异常。搜索到的类定义在编译当前执行的类时已经存在,但无法再找到该定义。

因此,似乎在成功编译源代码时会出现 NoClassDefFoundError,但在运行时,找不到所需的 class 文件。这可能是在 JAR 文件的分发或生产中可能发生的事情,其中并未包含所有必需的 class 文件。

至于 ClassNotFoundException,它似乎源于试图在运行时对类进行反射调用,但程序试图调用的类并不存在。

两者的区别在于一个是Error,另一个是ExceptionNoClassDefFoundErrorError,它是由 Java 虚拟机在查找它期望找到的类时遇到问题而引起的。由于未找到 class 个文件,或者与在编译时生成或遇到的文件不同,因此预期在编译时工作的程序无法运行。这是一个非常严重的错误,因为程序无法由 JVM 启动。

另一方面,ClassNotFoundException 是一个 Exception,因此在某种程度上是可以预期的,并且是可以恢复的。使用反射可能容易出错(因为有些期望事情可能不会按预期进行。没有编译时检查以查看所有必需的类是否存在,因此查找所需类的任何问题都会在运行时出现.


NoClassDefFoundError通常发生在类的静态块或静态字段初始化出现问题(抛出异常),导致类无法初始化成功。
赞成。一个是 Error,另一个是 Exception。 :)
D
David Lantos

当 ClassLoader 未找到报告的类时,将引发 ClassNotFoundException。这通常意味着 CLASSPATH 中缺少该类。这也可能意味着有问题的类正试图从另一个类加载,该类加载到父类加载器中,因此子类加载器中的类不可见。在更复杂的环境(如 App Server)中工作时有时会出现这种情况(WebSphere 因此类类加载器问题而臭名昭著)。

人们经常将 java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException 混淆,但有一个重要的区别。例如一个异常(一个真正的错误,因为 java.lang.NoClassDefFoundError 是 java.lang.Error 的子类),如

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

并不意味着 ActiveMQConnectionFactory 类不在 CLASSPATH 中。事实上它恰恰相反。这意味着 ClassLoader 找到了 ActiveMQConnectionFactory 类,但是在尝试加载该类时,它在读取类定义时遇到了错误。这通常发生在所讨论的类具有使用 ClassLoader 未找到的类的静态块或成员时。因此,要找到罪魁祸首,请查看相关类的源代码(在本例中为 ActiveMQConnectionFactory)并查找使用静态块或静态成员的代码。如果您无权访问源代码,则只需使用 JAD 对其进行反编译。

在检查代码时,假设您找到如下代码行,请确保类 SomeClass 在您的 CLASSPATH 中。

private static SomeClass foo = new SomeClass();

提示:要找出一个类属于哪个 jar,您可以使用网站 jarFinder。这允许您使用通配符指定类名,并在其 jar 数据库中搜索该类。 jarhoo 允许你做同样的事情,但它不再免费使用。

如果您想在本地路径中找到某个类所属的 jar,可以使用 jarscan ( http://www.inetfeedback.com/jarscan/ ) 之类的实用程序。您只需指定要查找的类以及您希望它开始在 jar 和 zip 文件中搜索类的根目录路径。


有趣的是,这是最后一个投票的完全正确答案。 (在我投票之前甚至是-1)。 ClassNotFoundException 表示 CL 看不到 .class 文件。 NoClassDefFoundError 表示 .class 文件在那里是不可加载的(可能是 JNI 错误)。
这个答案与 coobird 的答案不矛盾吗?
我尝试了类似的静态块示例。我的班级 Class1 有静态变量“private static B foo = new B();”编译后,我从 bin 文件夹中删除了 B.class 文件。现在,当我创建 Class1 的对象时,来自第三类的 Main 方法。错误如下所示:--------“线程“main”中的异常java.lang.NoClassDefFoundError:spring / B”........所以它准确地提到了它没有找到哪个类ieclass 在静态块中引用,而不是外部类。所以它与这个答案相反。
+1 用于澄清“并不意味着 ActiveMQConnectionFactory 类不在 CLASSPATH 中”
S
Stephen C

NoClassDefFoundError 基本上是一个链接错误。当您尝试实例化一个对象(静态地使用“new”)并且在编译期间找不到它时会发生这种情况。

ClassNotFoundException 更通用,当您尝试使用不存在的类时,它是一个运行时异常。例如,您在函数中有一个参数接受一个接口,并且有人传入了一个实现该接口的类,但您无权访问该类。它还涵盖了动态类加载的情况,例如使用 loadClass()Class.forName()


m
mogsie

当您的代码运行“new Y()”并且找不到 Y 类时,会发生 NoClassDefFoundError (NCDFE)。

可能只是像其他评论所暗示的那样,您的类加载器中缺少 Y,但可能是 Y 类未签名或签名无效,或者 Y 是由您的代码不可见的不同类加载器加载的,甚至 Y 依赖于 Z ,由于上述任何原因而无法加载。

如果发生这种情况,那么 JVM 将记住加载 X (NCDFE) 的结果,并且每次您请求 Y 时它都会简单地抛出一个新的 NCDFE,而不会告诉您原因:

class a {
  static class b {}
  public static void main(String args[]) {
    System.out.println("First attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
    System.out.println("\nSecond attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
  }
}

将其保存为 a.java 某处

该代码只是尝试两次实例化一个新的“b”类,除此之外,它没有任何错误,也没有做任何事情。

使用 javac a.java 编译代码,然后通过调用 java -cp . a 运行 a - 它应该只打印出两行文本,并且应该可以正常运行而没有错误。

然后删除“a$b.class”文件(或用垃圾填充它,或将a.class 复制到它上面)以模拟丢失或损坏的类。这是发生的事情:

First attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:5)
Caused by: java.lang.ClassNotFoundException: a$b
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    ... 1 more

Second attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:7)

第一次调用导致 ClassNotFoundException(由类加载器在找不到类时抛出),它必须包含在未经检查的 NoClassDefFoundError 中,因为有问题的代码 (new b()) 应该可以正常工作。

第二次尝试当然也会失败,但正如您所见,包装的异常不再存在,因为 ClassLoader 似乎记住了失败的类加载器。您只看到 NCDFE,完全不知道到底发生了什么。

因此,如果您看到没有根本原因的 NCDFE,您需要查看是否可以追溯到第一次加载类以找到错误原因。


使用 -verbose 或类似选项(取决于特定的 JVM)运行 JVM 怎么样?可能是 -verbose:class,如果使用 JNI,可能是 -verbose:class:jni,但我不确定语法。如果这有用,也许您可以显示结果。
-verbose:class-verbose:jni 都没有给出与缺失类相关的任何额外输出。
感谢您尝试,即使结果令人失望。 (PS 我后来发现 -verbose:class:jni 是错误的:必须指定两个单独的选项:-verbose:class -verbose:jni。)
最后一句 * 1,000,000:因此,如果您看到没有根本原因的 NCDFE,您需要查看是否可以追溯到第一次加载类以查找错误原因。
h
heenenee

http://www.javaroots.com/2013/02/classnotfoundexception-vs.html

ClassNotFoundException :当类加载器在类路径中找不到所需的类时发生。所以,基本上你应该检查你的类路径并将类添加到类路径中。

NoClassDefFoundError :这更难调试和查找原因。当在编译时存在所需的类,但在运行时更改或删除类或类的静态初始化时抛出异常。这意味着正在加载的类存在于类路径中,但是该类所需的类之一被删除或编译器无法加载。所以你应该看到依赖于这个类的类。

例子:

public class Test1
{
}


public class Test 
{
   public static void main(String[] args)
   {
        Test1 = new Test1();    
   }

}

现在编译完两个类后,如果你删除 Test1.class 文件并运行 Test 类,它会抛出

Exception in thread "main" java.lang.NoClassDefFoundError: Test
    at Test1.main(Test1.java:5)
Caused by: java.lang.ClassNotFoundException: Test
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    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

ClassNotFoundException:当应用程序尝试通过其名称加载类,但找不到具有指定名称的类的定义时抛出。

NoClassDefFoundError:如果 Java 虚拟机尝试加载类的定义并且找不到该类的定义,则抛出此错误。


使用 -verbose 或类似选项(取决于特定的 JVM)运行 JVM 怎么样?可能是 -verbose:class,如果使用 JNI,可能是 -verbose:class:jni,但我不确定语法。
-verbose:class:jni 是错误的,但您可以传递两个单独的选项:-verbose:class -verbose:jni
D
Donal Fellows

获取它们的原因是什么以及如何处理此类错误的任何思考过程?

它们密切相关。当 Java 按名称查找特定类但无法成功加载时,将引发 ClassNotFoundException。当 Java 寻找链接到某个现有代码的类时,会抛出 NoClassDefFoundError,但由于某种原因(例如,错误的类路径、错误的 Java 版本、错误的库版本)找不到它,并且是彻底致命的,因为它表明某些事情发生了严重错误。

如果您有 C 背景,CNFE 就像 dlopen()/dlsym() 失败,而 NCDFE 是链接器的问题;在第二种情况下,相关的类文件不应该在您尝试使用它们的配置中实际编译。


D
Dinesh

示例 #1:

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}

如果 com/example/Class1 不存在于任何类路径中,则它会抛出 ClassNotFoundException

示例 #2:

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}

如果在编译 B 时存在 com/example/Class2,但在执行时未找到,则它抛出 NoClassDefFoundError

两者都是运行时异常。


V
Vineet Reynolds

尝试通过字符串引用类来加载类时抛出 ClassNotFoundException。例如,Class.forName() 中的参数是一个字符串,这增加了将无效二进制名称传递给类加载器的可能性。

当遇到可能无效的二进制名称时,抛出 ClassNotFoundException;例如,如果类名有'/' 字符,你一定会得到一个ClassNotFoundException。当直接引用的类在类路径上不可用时,也会抛出它。

另一方面,NoClassDefFoundError 被抛出

当类的实际物理表示 - .class 文件不可用时,

或者该类已经在不同的类加载器中加载(通常父类加载器会加载该类,因此无法再次加载该类),

或者如果发现了不兼容的类定义 - 类文件中的名称与请求的名称不匹配,

或者(最重要的是)如果无法定位和加载依赖类。在这种情况下,可能已经定位并加载了直接引用的类,但依赖的类不可用或无法加载。在这种情况下,可以通过 Class.forName 或等效方法加载直接引用的类。这表明链接失败。

简而言之,当类加载器无法找到或加载类定义( s)。

最终,由 ClassLoader 实现在无法加载类时抛出 ClassNotFoundException 的实例。大多数自定义类加载器实现都执行此操作,因为它们扩展了 URLClassLoader。通常类加载器不会在任何方法实现上显式抛出 NoClassDefFoundError - 这个异常通常是从 HotSpot 编译器中的 JVM 抛出的,而不是由类加载器本身抛出的。


支持提及“类文件中的名称与请求的名称不匹配”。这是一个很常见的原因。
L
Lawakush Kurmi

ClassNotFoundException 与 NoClassDefFoundError 之间的区别

https://i.stack.imgur.com/n1TEp.png


不是晶莹剔透。 “未在类路径中更新”是模糊/不精确的。这与类路径中不存在 JAR 或类路径中的 JAR 版本错误有关。和拼写错误。并且(叹气)由于您将信息发布为时髦的图形,因此我们无法解决此问题。
P
Premraj

通过名称本身,我们可以很容易地识别出一个来自 Exception,另一个来自 Error。

异常:程序执行过程中出现异常。程序员可以通过 try catch 块来处理这些异常。我们有两种例外。在编译时抛出的检查异常。在运行时抛出的运行时异常,这些异常通常是由于糟糕的编程而发生的。

错误:这些根本不是例外,它超出了程序员的范围。这些错误通常由 JVM 抛出。

https://i.stack.imgur.com/1MhIb.jpg

区别:

类未发现异常:

类加载器无法验证链接中的字节码。

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

当通过在运行时使用 ClassLoader.loadClass()、Class.forName() 和 ClassLoader.findSystemClass() 提供类的名称来显式加载类时,会出现 ClassNotFoundException。

NoClassDefFoundError:

类加载器无法解析链接中类的引用。

NoClassDefFoundError 是从 LinkageError 类派生的错误,这是一个致命错误。当 JVM 在尝试使用 new 关键字实例化类或使用方法调用加载类时找不到类的定义时会发生这种情况。

NoClassDefFoundError 是由于来自该类的方法调用或任何变量访问而隐式加载类的结果。

相似之处:

NoClassDefFoundError 和 ClassNotFoundException 都与运行时类的不可用性有关。

ClassNotFoundException 和 NoClassDefFoundError 都与 Java 类路径有关。


A
Anton Shchastnyi

给定类加载器 sussystem 操作:

https://i.stack.imgur.com/V0kwG.gif

这是一篇帮助我理解差异的文章:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

如果在类加载期间发生错误,则必须在程序中(直接或间接)使用正在加载的类或接口的某个点处抛出 LinkageError 子类的实例。如果 Java 虚拟机在验证(第 5.4.1 节)或解析(第 5.4.3 节)(但不是初始化(第 5.5 节))期间尝试加载类 C,以及用于启动 C 加载的类加载器抛出 ClassNotFoundException 的实例,那么 Java 虚拟机必须抛出 NoClassDefFoundError 的实例,其原因是 ClassNotFoundException 的实例。

所以 ClassNotFoundException 是 NoClassDefFoundError 的根本原因。 NoClassDefFoundError 是类型加载错误的一种特殊情况,发生在链接步骤。


x
xea

在实践中添加一个可能的原因:

ClassNotFoundException:正如cletus所说,您使用接口,而接口的继承类不在类路径中。例如,服务提供者模式(或服务定位器)尝试定位一些不存在的类

NoClassDefFoundError:找到给定类,而没有找到给定类的依赖项

在实践中,错误可能会静默抛出,例如,你提交一个定时器任务,然后在定时器任务中抛出 Error,而在大多数情况下,您的程序只捕获 Exception。然后 Timer 主循环在没有任何信息的情况下结束。当您的静态初始化程序或静态变量的初始化程序抛出异常时,与 NoClassDefFoundError 类似的错误是 ExceptionInInitializerError


N
Naresh Joshi

ClassNotFoundException 是一个检查异常,当我们告诉 JVM 使用 Class.forName() 或 ClassLoader.findSystemClass() 或 ClassLoader.loadClass() 方法通过其字符串名称加载一个类并且在类路径中找不到提到的类时发生。

大多数情况下,当您尝试运行应用程序而不使用所需的 JAR 文件更新类路径时,会发生此异常。例如,在执行 JDBC 代码连接到数据库 ieMySQL 时,您可能已经看到此异常,但您的类路径没有 JAR。

NoClassDefFoundError 错误发生在 JVM 尝试加载作为代码执行一部分的特定类(作为正常方法调用的一部分或作为使用 new 关键字创建实例的一部分)并且该类不存在于您的类路径中但在编译时存在,因为为了执行您的程序,您需要编译它,如果您尝试使用不存在的类,编译器将引发编译错误。

以下是简要说明

https://i.stack.imgur.com/POZ0x.png

您可以阅读 Everything About ClassNotFoundException Vs NoClassDefFoundError 了解更多详情。


S
Sankarganesh Eswaran

当我需要刷新时,我一次又一次地提醒自己以下几点

ClassNotFoundException

类层次结构

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

调试时

必需的 jar,类路径中缺少类。验证所有必需的 jar 都在 jvm 的类路径中。

NoClassDefFoundError

类层次结构

NoClassDefFoundError extends LinkageError  extends Error extends Throwable

调试时

动态加载类的问题,该类已正确编译 静态块,构造函数,依赖类的 init() 方法的问题,实际错误被多层包裹[特别是当您使用弹簧时,休眠实际异常被包裹,您将get NoClassDefError] 当您在依赖类的静态块下遇到“ClassNotFoundException”时,类的版本有问题。当您在不同的 jar/包下有相同类的两个版本 v1、v2 时会发生这种情况,这些版本使用 v1 成功编译,并且 v2 在没有相关方法/变量的运行时加载,您将看到此异常。 [我曾经通过删除类路径中出现的多个 jar 下的 log4j 相关类的副本来解决此问题]


N
Neeraj Gahlawat

ClassNotFoundException 和 NoClassDefFoundError 在运行时找不到特定类时发生。但是,它们发生在不同的场景中。

ClassNotFoundException 是当您尝试在运行时使用 Class.forName() 或 loadClass() 方法加载类并且在类路径中找不到所提到的类时发生的异常。

    public class MainClass
    {
        public static void main(String[] args)
        {
            try
            {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }



    java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
    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)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError 是在编译时存在特定类但在运行时丢失时发生的错误。

    class A
    {
      // some code
    }
    public class B
    {
        public static void main(String[] args)
        {
            A a = new A();
        }
    }

编译上述程序时,会生成两个 .class 文件。一个是A.class,另一个是B.class。如果删除 A.class 文件并运行 B.class 文件,Java 运行时系统将抛出 NoClassDefFoundError 如下所示:

    Exception in thread "main" java.lang.NoClassDefFoundError: A
    at MainClass.main(MainClass.java:10)
    Caused by: java.lang.ClassNotFoundException: A
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)