是什么原因以及NoClassDefFoundError和ClassNotFoundException之间有什么区别?

时间:2009-09-22 02:29:36

标签: java classpath noclassdeffounderror classnotfoundexception

NoClassDefFoundErrorClassNotFoundException之间的区别是什么?

是什么导致他们被抛出?他们怎么解决?

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

我遇到的可能原因:

  1. 代码
  2. 的客户端build.xml中未包含的软件包
  3. 我们正在使用的新罐子缺少运行时类路径
  4. 版本与之前的jar冲突
  5. 今天遇到这些时,我采取了一种追踪错误的方法来让事情顺利进行。我需要更清晰和理解。

14 个答案:

答案 0 :(得分:379)

与Java API规范的区别如下。

ClassNotFoundException

  

应用程序尝试时抛出   通过字符串加载一个类   名字使用:

     
      
  • 班级forName中的Class方法。
  •   
  • 班级findSystemClass中的ClassLoader方法。
  •   
  • 班级loadClass中的ClassLoader方法。
  •   
     

但没有该类的定义   可以找到指定的名称。

NoClassDefFoundError

  

如果是Java虚拟机,则抛出   ClassLoader实例尝试加载   在一个类的定义中(作为一部分   正常方法调用或作为一部分   使用new创建一个新实例   表达式)并没有定义   可以找到课程。

     

搜索的类定义   当前执行时存在   类被编译,但定义   再也找不到了。

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

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

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

另一方面,ClassNotFoundExceptionException,因此有点预期,并且是可以恢复的。使用反射可能容易出错(因为有些期望事情可能没有按预期进行。没有编译时检查以查看所有必需的类都存在,因此找到所需类的任何问题都将在运行时出现

答案 1 :(得分:80)

当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对其进行反编译。

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

private static SomeClass foo = new SomeClass();

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

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

答案 2 :(得分:33)

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

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

答案 3 :(得分:29)

当您的代码运行“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 $ 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,您需要查看是否可以追溯到第一次加载类以查找错误原因。

答案 4 :(得分:19)

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

答案 5 :(得分:15)

  

获取每个问题以及如何处理此类错误的思考过程的原因是什么?

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

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

答案 6 :(得分:9)

当尝试通过String引用类来加载类时,抛出

ClassNotFoundException。例如,Class.forName()中的参数是一个String,这会增加传递给类加载器的无效二进制名称的可能性。

遇到可能无效的二进制名称时抛出ClassNotFoundException;例如,如果类名具有“/”字符,则必然会得到ClassNotFoundException。当直接引用的类在类路径上不可用时,它也会抛出。

另一方面,NoClassDefFoundError被抛出

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

简而言之,当类加载器无法找到或加载时,通常会在加载以前缺少的类的new()语句或方法调用上抛出NoClassDefFoundError(与ClassNotFoundException的基于字符串的类加载相反)。类定义。

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

答案 7 :(得分:8)

ClassNotFoundException与NoClassDefFoundError之间的区别

enter image description here

答案 8 :(得分:7)

  

通过名称本身,我们可以轻松识别Exception中的一个,而另一个来自Error

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

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

enter image description here image source

<强>差:

<强> ClassNotFoundException的:

  • 类加载器无法验证我们在类加载子系统链接阶段中提到的类字节代码,我们得到ClassNotFoundException
  • ClassNotFoundException是直接从java.lang.Exception类派生的已检查异常,您需要为其提供显式处理
  • 通过使用ClassLoader.loadClass(),Class.forName()和ClassLoader.findSystemClass在运行时提供类的名称,当涉及显式加载类时,
  • ClassNotFoundException出现()。

NoClassDefFoundError:

  • 类加载器未能解析 类加载子系统链接阶段中的类的引用,我们得到NoClassDefFoundError
  • NoClassDefFoundError是从LinkageError类派生的错误,用于指示错误情况,其中一个类依赖于某个其他类,并且该类在编译后不兼容地更改。
  • NoClassDefFoundError隐式加载的结果,因为来自该类或任何变量访问的方法调用。

相似之处:

  • NoClassDefFoundErrorClassNotFoundException都与运行时类的不可用性有关。
  • ClassNotFoundExceptionNoClassDefFoundError都与Java classpath相关。

答案 9 :(得分:3)

给定类加载器sussystem操作:

http://www.artima.com/insidejvm/ed2/images/fig7-1.gif

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

  

如果在类加载期间发生错误,那么a的实例   必须在程序中的某个点抛出 LinkageError 的子类   (直接或间接)使用正在加载的类或接口。

     

如果Java虚拟机曾尝试在期间加载C类   验证(§5.4.1)或解决方案(§5.4.3)(但不是初始化   (§5.5)),以及用于启动C加载的类加载器   抛出 ClassNotFoundException 的实例,然后抛出Java Virtual   Machine必须抛出一个 NoClassDefFoundError 的实例,其原因是    ClassNotFoundException 的实例。

因此 ClassNotFoundException NoClassDefFoundError 的根本原因。 NoClassDefFoundError 是类型加载错误的特例,发生在链接步骤。

答案 10 :(得分:2)

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

  • ClassNotFoundException:正如cletus所说,你使用接口而继承的接口类不在classpath中。例如,服务提供商模式(或Service Locator)尝试找到一些不存在的类
  • NoClassDefFoundError:在找不到给定类的依赖关系时找到给定的类

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

答案 11 :(得分:1)

当我需要刷新时,我会一次又一次地提醒自己

<强> ClassNotFoundException的

类层次结构

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

调试时

  1. 类路径中缺少必需的jar类。
  2. 验证所有必需的jar都在jvm的类路径中。
  3. <强> NoClassDefFoundError的

    类层次结构

    NoClassDefFoundError extends LinkageError  extends Error extends Throwable
    

    调试时

    1. 动态加载类的问题,已正确编译
    2. 依赖类的静态块,构造函数,init()方法的问题和实际错误被多个层包装[​​特别是当你使用spring时,hibernate实际异常被包装,你将得到NoClassDefError]
    3. 当你面对&#34; ClassNotFoundException&#34;在依赖类的静态块下
    4. 课程版本的问题。 当你在不同的jar /包下有两个版本的同一类v1,v2时会发生这种情况,这是使用v1成功编译而v2是在运行时加载的,它没有相关的方法/ vars&amp;你会看到这个例外。 [我曾经通过删除类路径中出现的多个jar下的log4j相关类的副本来解决这个问题]

答案 12 :(得分:1)

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

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

当JVM尝试加载作为代码执行一部分的特定类时(作为普通方法调用的一部分或使用new关键字创建实例的一部分),会发生

NoClassDefFoundError 错误该类不在您的类路径中,但在编译时出现,因为为了执行您的程序,您需要编译它,如果您尝试使用不存在的类,编译器将引发编译错误。

以下是简要说明

enter image description here

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

答案 13 :(得分:0)

在运行时未找到特定类时会发生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 Runtime System将抛出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)