ClassNotFoundException与NoClassDefFoundError

我已经完成了这个线程是什么原因以及NoClassDefFoundError和ClassNotFoundException之间有什么区别? 这是一个在线程中具有max ups的ans之一: NoClassDefFoundError :“因此,看起来在成功编译源时会发生 NoClassDefFoundError ,但是在运行时,找不到所需的类文件 。这可能是在分发或生成JAR文件时可能发生的事情,其中​​并未包含所有必需的类文件。“

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

我做了一个小实验。 我创建了一个主类, 类A并尝试从中调用其他类,类B ,编译成功。

然后我删除了在类A中调用的类B.我得到了java.lang.ClassNotFoundException但是根据步骤中的答案,我应该得到NoClassDefFoundError(源代码已成功编译但未找到运行时类文件)任何人都可以解释我在线程中对ans的解释中缺少什么吗?

package com.random; public class A { public static void main(String[] args) { B b= new B(); } } package com.random; public class B { } 

的NoClassDefFoundError

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

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


ClassNotFoundException的

当应用程序尝试使用以下方法通过其字符串名称加载类时抛出:Class类中的forName方法。 类ClassLoader中的findSystemClass方法。 类ClassLoader中的loadClass方法。


您必须了解JVM无法实现您删除的class的定义无法找到,因为无法找到class本身会自动抛出ClassNotFoundException

此exception发生在runtime因此无论是否首先编译都没关系,您删除了文件,因此无法找到它并抛出exception

请注意, NoClassDefFoundError实际上不是exception,它是从LinkageError派生的Error ,而ClassNotFoundException直接从java.lang.Exception派生。

要恢复, NoClassDefFoundError全局只是意味着JVM试图在runtime访问根据compiled代码存在的东西,但实际上并不存在(或者不在类路径中)。


重现ClassNotFoundException的示例

 public class ClassNotFoundExceptionExample { private static final String CLASS_TO_LOAD = "main.java.Utils"; public static void main(String[] args) { try { Class loadedClass = Class.forName(CLASS_TO_LOAD); System.out.println("Class " + loadedClass + " found successfully!"); } catch (ClassNotFoundException ex) { System.err.println("A ClassNotFoundException was caught: " + ex.getMessage()); ex.printStackTrace(); } } } 

重现NoClassDefFoundError的示例

创建一个简单的类Test

 public class Test { public Test() { System.out.println("A new instance of the Test class was created!"); } } 

还有一个NoClassDefFoundErrorExample

 public class NoClassDefFoundErrorExample { private static Test test = new Test(); public static void main(String[] args) { System.out.println("The definition of Test was found!"); } } 

现在创建一个执行main方法的可执行文件.jar 。 您可以在.jar中的Manifest.txt文件中指定它

 Main-Class: NoClassDefFoundErrorExample 

现在运行以下命令

 javac Test.java javac NoClassDefFoundErrorExample.java jar cfm NoClassDefFoundErrorExample.jar Manifest.txt NoClassDefFoundErrorExample.class java -jar NoClassDefFoundErrorExample.jar 

注意NoClassDefFoundError

 Exception in thread "main" java.lang.NoClassDefFoundError: TestClass at NoClassDefFoundErrorExample.(NoClassDefFoundErrorExample.java:2) Caused by: java.lang.ClassNotFoundException: TestClass at java.net.URLClassLoader$1.run(URLClassLoader.java:372) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:360) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 1 more 

嗯… ClassNotFoundException发生在运行时试图找到某个String命名的类时,例如Class.forName(java.lang.String)方法接受一个字符串参数并尝试查找具有此名称的类。 在这种情况下,类名是一个sting,只能在运行时检查。 这里的例外清楚地说……没有找到这个“阶级”。 所以……它可能有两个原因:

原因1.类名不是有效的java类(例如“java.bang.kiting”)。

 // Example Class cdef = Class.forName( "java.bang.kiting" ); 

原因2.类名是一个有效的类…但不知何故它没有与jar打包或在类路径中没有解析。 因此,就运行时所知…它可能是一个错误的类名…类似于案例1。

 // Example Class cdef =Class.forName( "apache.some.SomeLegitClass" ); 

对于使用实际类引用的情况, NoClassDefFoundError的位置,

 // example import apache.some.SomeLegitClass SomeLegitClass i = (SomeLegitClass) instanceOfSomeLegitClass; 

所以基本上一切都是正确的,但不知何故,这个类没有与jar打包(或者更一般地说 – 在类路径中没有解决)。 在这种情况下,我们得到NoClassDefFoundError

这里运行时知道该类是有效的,因为它已成功编译…但它找不到“类定义”。

差异取决于谁要求加载课程

  • 当代码直接尝试加载类时抛出ClassNotFoundException ,传递表示类的完全限定名称的String参数。
    • 例如Class.forName(String)ClassLoader.loadClass(String)
  • 当要求JVM间接加载类时,抛出NoClassDefFoundError
    • 例如,当A类使用B类而B类不在类路径上时,将抛出NoClassDefFoundError

当您使用库(例如,Guava,Gson,CommonsIO)时,通常会调用NoClassDefFoundError 。 您将库放在项目的类路径中,但是没有将它一起导出,当应用程序运行时,您将获得NoClassDefFoundError

如何获取NoClassDefFoundError
使用此类创建一个新项目。

 public class A { public void do() { System.out.println("Do!"); } } 

将其导出为.jar文件。

现在创建另一个项目。 将导出的jar文件添加到classpath。

 import ???.A; public class Main { public static void main(String[] args) { A a = new A(); a.do();//NoClassDefFoundError thrown at here. } } 

导出项目,确保不包含jar文件(使用A类)。 运行新导出的jar文件,您将看到该错误!

1) ClassNotFoundException

  1. 当我们尝试使用Class.forName()ClassLoader.loadClass()ClassLoader.findSystemClass()方法在运行时加载类时,会发生这种情况,并且无法类路径中找到所需的
  2. 在这种情况下,我们应检查class path并在class path添加类(如果缺少)。
  3. 这是一个经过检查的Exception ,它派生自java.lang.Exception类。
  4. 这是明确的加载。

2) NoClassDefFoundError

  1. 当类在compile time期间compile time并且由于某些原因在run time期间不可用时,会发生这种情况。 这意味着正在加载的类presentclasspath ,但是此类所需的其中一个依赖的classe(s)要么被删除 ,要么编译器加载失败

  2. 在这种情况下,我们只需要检查classes which are dependent on this class

  3. 这是一个错误 ,它源自java.lang.LinkageError
  4. 这是隐式加载。

如前面的答案中所述,当在编译期间出现类时,NoClassDefFoundError将发生,并且由于某些原因在运行时期间不可用。

我想添加另一个场景,这也可能导致NoClassDefFoundError。

当您尝试加载由于某些exception而无法加载的类时,表示静态初始化块失败,系统将抛出ExceptionInInitializerError。 如果您尝试再次加载相同的类(以前无法加载),系统将抛出NoClassDefFoundError

让我们用一个样本来探索它

ClassWithStaticBlock.java

 public class ClassWithStaticBlock { static { int total = 1/0; } } 

Main.java

 public class Main { public static void main(String[] args) { ClassWithStaticBlock cs; try { cs = new ClassWithStaticBlock(); }catch(Throwable e){ e.printStackTrace(); } } } 

结果:

 java.lang.ExceptionInInitializerError at Main.main(Main.java:6) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: java.lang.ArithmeticException: / by zero at ClassWithStaticBlock.(ClassWithStaticBlock.java:7) ... 6 more 

让我们修改Main.java

 public class Main { public static void main(String[] args) { ClassWithStaticBlock cs; try { cs = new ClassWithStaticBlock(); }catch(Throwable e){ e.printStackTrace(); } cs = new ClassWithStaticBlock(); //try to use ClassWithStaticBlock again } } 

结果:

 java.lang.ExceptionInInitializerError at Main.main(Main.java:6) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: java.lang.ArithmeticException: / by zero at ClassWithStaticBlock.(ClassWithStaticBlock.java:7) ... 6 more Exception in thread "Main Thread" java.lang.NoClassDefFoundError: ClassWithStaticBlock at Main.main(Main.java:10) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

当我们再次尝试使用ClassWithStaticBlock时(之前未能初始化),System正在抛出NoClassDefFoundError。

找到了我为什么在Java中获得NoClassDefFoundError的示例?

发生NoClassDefFoundError的情况之一是在类路径中找不到类JVM尝试访问的情况。 但是如果类存在于类路径中,则会导致ClassNotFoundException。

简而言之,如果在编译期间存在类但在运行时期间在java类路径中不可用,则会出现NoClassDefFoundError。

只是尝试使用显式-classpath选项运行,其中类路径不包含类B.

在运行时未找到特定类时会发生ClassNotFoundException和NoClassDefFoundError。但是,它们出现在不同的方案中。

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

 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) 

关于ClassNotFoundException的所有内容与NoClassDefFoundError文章一起解释了ClassNotFoundException和NoClassDefFoundError之间的区别,并且根据它非常清楚。

ClassNotFoundException与NoClassDefFoundError  - 编程Mitra

ClassNotFoundException的

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

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

 public class Test { public static void main(String[] args) throws Exception { // Provide any class name to Class.forName() which does not exist // Or compile Test.java and then manually delete Person.class file so Person class will become unavailable // Run the program using java Test Class clazz = Class.forName("Person"); Person person = (Person) clazz.newInstance(); person.saySomething(); } } class Person { void saySomething() { System.out.println("Hello"); } } 

的NoClassDefFoundError

是java.lang.Error的子类型,而Error类表示应用程序实际上不应该发生的exception行为,但应用程序开发人员不应该尝试捕获它,它只适用于JVM。

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

 public class Test { public static void main(String[] args) throws Exception { // Do javac on Test.java, // Program will compile successfully because Empoyee class exits // Manually delete Employee.class file // Run the program using java Test Employee emp = new Employee(); emp.saySomething(); } } class Employee { void saySomething() { System.out.println("Hello"); } } 

这个post中的其他答案是正确的,我只想添加一些我花费数小时试图找出的东西。 即使

 Class.forName("apache.some.SomeLegitClass") 

作品,

 Class.forName("apache.some.somelegitclass") 

将导致NoClassDefFoundError。 Class.forName()区分大小写。 如果类名拼写错误,或者只是包含不正确的大小写,则会导致不同的exception。