384

NoClassDefFoundError和 和有什么不一样ClassNotFoundException

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

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

我遇到的可能原因:

  1. 不包含在build.xml客户端代码中的包
  2. 我们正在使用的新 jar 缺少运行时类路径
  3. 版本与之前的 jar 冲突

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

4

15 回答 15

392

与 Java API 规范的区别如下。

对于ClassNotFoundException

当应用程序尝试通过其字符串名称加载类时抛出:

  • 类中的forName方法Class
  • 类中的findSystemClass方法ClassLoader
  • 类中的loadClass方法ClassLoader

但找不到具有指定名称的类的定义。

对于NoClassDefFoundError

如果 Java 虚拟机或ClassLoader实例尝试加载类的定义(作为正常方法调用的一部分或作为使用 new 表达式创建新实例的一部分)并且找不到类的定义,则抛出此异常。

搜索到的类定义在编译当前执行的类时已经存在,但无法再找到该定义。

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

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

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

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

于 2009-09-22T02:37:19.330 回答
83

当 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 文件中搜索类的根目录路径。

于 2010-02-06T14:55:55.113 回答
37

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

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

于 2009-09-22T02:36:57.317 回答
30

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

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

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

类{
  静态类 b {}
  公共静态无效主要(字符串参数[]){
    System.out.println("第一次尝试 new b():");
    试试 {新 b(); } catch(Throwable t) {t.printStackTrace();}
    System.out.println("\n第二次尝试 new b():");
    试试 {新 b(); } catch(Throwable t) {t.printStackTrace();}
  }
}

将其保存为 a.java 某处

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

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

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

第一次尝试新 b():
java.lang.NoClassDefFoundError: a$b
    在 a.main(a.java:5)
引起:java.lang.ClassNotFoundException:a$b
    在 java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    在 java.security.AccessController.doPrivileged(本机方法)
    在 java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    在 java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    在 java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    在 java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    ... 1 更多

第二次尝试新 b():
java.lang.NoClassDefFoundError: a$b
    在 a.main(a.java:7)

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

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

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

于 2010-07-07T20:21:48.213 回答
20

来自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 虚拟机尝试加载类的定义并且找不到该类的定义,则抛出该错误。

于 2014-09-24T04:39:58.413 回答
15

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

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

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

于 2010-07-07T21:04:07.330 回答
11

示例 #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();
 }
}

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

两者都是运行时异常。

于 2015-01-12T17:31:01.267 回答
9

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

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

另一方面,抛出NoClassDefFoundError

  • 当类的实际物理表示 - .class 文件不可用时,
  • 或者该类已经在不同的类加载器中加载(通常父类加载器会加载该类,因此无法再次加载该类),
  • 或者如果发现了不兼容的类定义 - 类文件中的名称与请求的名称不匹配,
  • 或者(最重要的是)如果无法定位和加载依赖类。在这种情况下,可能已经定位并加载了直接引用的类,但依赖的类不可用或无法加载。在这种情况下,可以通过 Class.forName 或等效方法加载直接引用的类。这表明链接失败。

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

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

于 2009-09-22T03:22:09.530 回答
9

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

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

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


在此处输入图像描述 图片来源

不同之处:

类未发现异常:

  • 类加载器无法验证Linking中的字节码。
  • ClassNotFoundException是一个检查异常,当应用程序尝试通过其完全限定名称加载类并且无法在类路径上找到其定义时发生。
  • ClassNotFoundException当通过在运行时使用 ClassLoader.loadClass()、Class.forName() 和 ClassLoader.findSystemClass() 提供类的名称来涉及类的显式加载时,就会出现。

NoClassDefFoundError:

  • 类加载器无法解析Linking中类的引用。
  • NoClassDefFoundError是从LinkageError类派生的错误,这是一个致命错误。当 JVM 在尝试使用 new 关键字实例化类或使用方法调用加载类时找不到类的定义时会发生这种情况。
  • NoClassDefFoundError是由于来自该类的方法调用或任何变量访问而隐式加载类的结果。

相似之处:

  • 两者都NoClassDefFoundErrorClassNotFoundException运行时类的不可用有关。
  • 两者都ClassNotFoundExceptionNoClassDefFoundErrorJava 类路径有关。
于 2015-12-30T01:00:03.817 回答
9

ClassNotFoundException 与 NoClassDefFoundError 之间的区别

在此处输入图像描述

于 2016-01-31T19:15:58.017 回答
3

给定类加载器 sussystem 操作:

http://www.artima.com/insidejvm/ed2/images/fig7-1.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的实例。

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

于 2015-01-20T09:57:39.920 回答
2

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

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

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

于 2012-02-17T04:36:52.097 回答
2

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

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

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

以下是简要说明

在此处输入图像描述

您可以阅读有关ClassNotFoundException Vs NoClassDefFoundError 的所有信息以获取更多详细信息。

于 2017-04-08T13:29:14.410 回答
0

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

ClassNotFoundException

类层次结构

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

调试时

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

NoClassDefFoundError

类层次结构

NoClassDefFoundError extends LinkageError  extends Error extends Throwable

调试时

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

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)
于 2017-08-18T09:29:41.620 回答