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

kri*_*isp 364 java classpath noclassdeffounderror classnotfoundexception

NoClassDefFoundError和之间有什么区别ClassNotFoundException

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

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

我遇到的可能原因:

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

当我今天遇到这些时,我采取了一种线索和错误的方法来使事情发挥作用.我需要更清晰和理解.

coo*_*ird 385

与Java API规范的不同之处如下.

用于ClassNotFoundException:

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

  • forName课堂上的方法Class.
  • findSystemClass课堂上的方法ClassLoader.
  • loadClass课堂上的方法ClassLoader.

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

用于NoClassDefFoundError:

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

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

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

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

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

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

  • 当NoClassDefFoundError`出现问题(抛出异常)时,通常会发生类的静态块或静态字段初始化,因此无法成功初始化类. (53认同)
  • 给予好评.一个是"错误",另一个是"异常".:) (7认同)

San*_*van 82

当ClassLoader找不到报告的类时,抛出ClassNotFoundException.这通常意味着CLASSPATH中缺少该类.它也可能意味着有问题的类试图从另一个加载在父类加载器中的类加载,因此子类加载器中的类是不可见的.在像App Server这样的更复杂的环境中工作时有时就是这种情况(WebSphere对于这样的类加载器问题是臭名昭着的).

人们往往倾向于混淆java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException然而,有一个重要的区别.例如一个异常(一个错误,因为它java.lang.NoClassDefFoundError是java.lang.Error的子类)就像

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory
Run Code Online (Sandbox Code Playgroud)

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

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

private static SomeClass foo = new SomeClass();
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我很有趣,这是完全正确的答案投票的最后一个.(在我投票之前甚至是-1).ClassNotFoundException意味着CL没有看到.class文件.NoClassDefFoundError意味着.class文件在那里它是不可加载的(可能是JNI错误). (8认同)

cle*_*tus 35

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

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


mog*_*sie 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中,因为question(new b())中的代码应该正常工作.

第二次尝试当然也会失败,但是你可以看到包装的异常不再存在,因为ClassLoader似乎记得失败的类加载器.你只看到NCDFE完全不知道究竟发生了什么.

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

  • 最后一句* 1,000,000:**因此,如果您看到无根本原因的NCDFE,则需要查看是否可以追溯到第一次加载类时才查找错误原因。** (2认同)

Kin*_*ing 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();    
   }

}
Run Code Online (Sandbox Code Playgroud)

现在编译完两个类后,如果删除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
Run Code Online (Sandbox Code Playgroud)

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

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


Don*_*ows 15

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

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

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

  • 这可能是整个线程+1的最佳答案 (3认同)

Din*_*esh 11

示例#1:

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}
Run Code Online (Sandbox Code Playgroud)

如果com/example/Class1在任何类路径中都不存在,那么它会抛出ClassNotFoundException.

示例#2:

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}
Run Code Online (Sandbox Code Playgroud)

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

两者都是运行时异常.


Vin*_*lds 9

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

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

另一方面,抛出NoClassDefFoundError

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

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

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


Pre*_*raj 8

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

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

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


在此输入图像描述 图像源

区别:

ClassNotFoundException的:

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

NoClassDefFoundError的:

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

相似点:

  • 双方NoClassDefFoundErrorClassNotFoundException都与在运行时类不可用.
  • 双方ClassNotFoundExceptionNoClassDefFoundError都与Java类路径.


小智 8

ClassNotFoundException与NoClassDefFoundError之间的区别

在此输入图像描述