什么原因导致NoClassDefFoundError和ClassNotFoundException之间有什么区别?

北城以北 提交于 2020-02-26 09:54:35

NoClassDefFoundErrorClassNotFoundException什么区别?

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

在修改现有代码以包含新的jar文件时,我经常遇到这些throwables。 我在客户端和服务器端都通过Webstart分发了一个Java应用程序。

我遇到的可能原因:

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

今天,当我遇到这些问题时,我采取了走错一步的方法来使事情顺利进行。 我需要更多的清晰度和理解。


#1楼

NoClassDefFoundError基本上是一个链接错误。 当您尝试实例化一个对象时会发生这种情况(静态地使用“ new”),而在编译过程中则找不到该对象。

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


#2楼

与Java API规范的区别如下。

对于ClassNotFoundException

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

  • ClassforName方法。
  • ClassLoaderfindSystemClass方法。
  • ClassLoaderloadClass方法。

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

对于NoClassDefFoundError

如果Java虚拟机或ClassLoader实例尝试加载类的定义(作为常规方法调用的一部分或使用新表达式创建新实例的一部分)而抛出,则ClassLoader的定义。

当前正在编译的类在编译时就存在搜索到的类定义,但是无法再找到该定义。

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

至于ClassNotFoundException ,似乎是由于试图在运行时对类进行反射性调用而引起的,但程序尝试调用的类不存在。

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

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


#3楼

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

当遇到可能无效的二进制名称时,将引发ClassNotFoundException; 例如,如果类名带有'/'字符,则势必会收到ClassNotFoundException。 当直接引用的类在类路径上不可用时,也会抛出该错误。

另一方面,抛出NoClassDefFoundError

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

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

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


#4楼

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

人们通常倾向于将java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException混淆,但是有一个重要的区别。 例如一个异常(实际上是一个错误,因为java.lang.NoClassDefFoundErrorjava.lang.NoClassDefFoundError的子类)

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


#5楼

来自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 class,它将抛出

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!