ClassNotFoundException 与 NoClassDefFoundError
Posted
技术标签:
【中文标题】ClassNotFoundException 与 NoClassDefFoundError【英文标题】:ClassNotFoundException vs NoClassDefFoundError 【发布时间】:2015-04-04 01:27:36 【问题描述】:我已经通过这个线程What causes and what are the differences between NoClassDefFoundError and ClassNotFoundException? 这就是线程中具有最大 ups 的 ans 之一是: NoClassDefFoundError :"所以,看来NoClassDefFoundError发生在源码编译成功时,但在运行时找不到所需的类文件。这可能是可以发生在 JAR 文件的分发或生产中,其中并未包含所有必需的类文件。”
ClassNotFoundException:至于ClassNotFoundException,看来它可能源于试图在运行时对类进行反射调用,但程序试图调用的类并不存在。
我做了一个小实验。我创建了一个主类 class A 并尝试从中调用其他类 class 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
【问题讨论】:
有趣,因为另一个站点做了同样的测试,得到了你想要的结果:javaroots.com/2013/02/classnotfoundexception-vs.html 我很想知道如果您将 B 类放在不同的包中然后必须在 A 类中包含import com.random.blah.B;
会发生什么。
有趣。删除 B.class 后,我得到了这个: 线程“main”中的异常 java.lang.NoClassDefFoundError: com/random/B at com.random.A.main(A.java:6) Caused by: java.lang.ClassNotFoundException: com.random.B
【参考方案1】:
NoClassDefFoundError
如果 Java 虚拟机或 ClassLoader 实例尝试 加载类的定义(作为正常方法调用的一部分或 作为使用 new 表达式创建新实例的一部分)并且没有 可以找到类的定义。
搜索到的类定义在当前执行时存在 类已编译,但无法再找到定义。
ClassNotFoundException
当应用程序尝试通过其字符串加载类时抛出 名称使用:Class 类中的 forName 方法。查找系统类 ClassLoader 类中的方法。类中的loadClass方法 类加载器。
你要明白JVM
无法实现你删除的class
的定义找不到,因为class
本身找不到会自动抛出ClassNotFoundException
。
这个异常发生在runtime
,所以不管它是否先编译,你删除了文件,因此找不到它并抛出exception
。
请注意,NoClassDefFoundError
实际上并不是一个例外,它是从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!");
现在创建一个可执行的.jar
来执行main
方法。您可以在.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
【讨论】:
堆栈跟踪错误地抱怨TestClass
,而它应该提到Test
。【参考方案2】:
嗯...ClassNotFoundException
发生在运行时试图查找由某些String
命名的类时,例如Class.forName(java.lang.String)
方法采用字符串参数并尝试查找具有该名称的类。在这种情况下,类名是一个字符串,只能在运行时检查。这里的异常清楚地表明......没有找到这个“类”。所以...这可能有两个原因:
原因 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
。
这里运行时知道该类是有效的,因为它编译成功...但是它找不到“类定义”。
【讨论】:
"这里runtime知道类是有效的,因为编译成功了……但是找不到“类定义”——这一行就是这个ans的精髓【参考方案3】:区别取决于谁要求加载类:
ClassNotFoundException
在代码直接尝试加载类时抛出,传递代表类的完全限定名称的String
参数。
例如Class.forName(String)
,或ClassLoader.loadClass(String)
。
NoClassDefFoundError
在要求 JVM 间接加载类时抛出。
例如当 A 类使用 B 类且 B 类不在类路径上时,将抛出 NoClassDefFoundError
。
【讨论】:
【参考方案4】:NoClassDefFoundError
通常在您使用库时调用(例如,Guava、Gson、CommonsIO)。您将库放在项目的类路径中,但您没有将它一起导出,当应用程序运行时您会得到一个NoClassDefFoundError
。
如何获得NoClassDefFoundError
:
使用此类创建一个新项目。
public class A
public void do()
System.out.println("Do!");
将其导出为.jar
file。
现在创建另一个项目。将导出的 jar 文件添加到类路径。
import ???.A;
public class Main
public static void main(String[] args)
A a = new A();
a.do();//NoClassDefFoundError thrown at here.
导出项目,确保不包含 jar 文件(类 A
)。运行新导出的jar文件,你会看到那个错误!
【讨论】:
【参考方案5】:Everything About ClassNotFoundException Vs NoClassDefFoundError 文章通过示例和根据它非常清楚地解释了 ClassNotFoundException Vs NoClassDefFoundError 之间的区别。
ClassNotFoundException
当我们告诉 JVM 使用 Class.forName() 或 ClassLoader.findSystemClass() 或 ClassLoader.loadClass() 方法通过其字符串名称加载类并且在类路径中找不到提到的类时,会发生检查异常。
大多数情况下,当您尝试运行应用程序而不使用所需的 JAR 文件更新类路径时会发生此异常。例如,在执行 JDBC 代码连接到数据库(即 mysql)时,您可能已经看到此异常,但您的类路径没有对应的 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 类表示应用程序确实不应该发生的异常行为,但应用程序开发人员不应该尝试捕捉它,它仅供 JVM 使用。
NoClassDefFoundError 发生在 JVM 尝试加载作为代码执行一部分的特定类(作为普通方法调用的一部分或作为使用 new 关键字创建实例的一部分)并且该类不存在于类路径中时但在编译时存在,因为为了执行您的程序,您需要对其进行编译,如果您尝试使用不存在的类,编译器将引发编译错误。
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");
【讨论】:
【参考方案6】:1) ClassNotFoundException
-
当我们尝试在运行时使用
Class.forName()
或 ClassLoader.loadClass()
或 ClassLoader.findSystemClass()
方法加载一个类时,它可能找不到在 中找到所需的类类路径。
在这种情况下,我们应该检查class path
,如果缺少该类,则将其添加到类路径中。
这是一个checked Exception,它派生自java.lang.Exception类。
这属于显式加载。
2) NoClassDefFoundError
当类在 compile time
期间存在并且由于某些原因在 run time
期间不可用时,会发生这种情况。这意味着正在加载的类是 classpath
中的 present
,但是此类所需的依赖 classe(s)
之一是 removed 或 failed由编译器加载。
在这种情况下,我们只需要检查classes which are dependent on this class
即可。
【讨论】:
它总是令人困惑。在给定的例子中,B类被A类间接引用。A类依赖于B类,所以它应该抛出NoClassDefFoundError。【参考方案7】:如之前的答案中所述,当类在编译期间存在并且由于某些原因在运行期间不可用时,将发生 NoClassDefFoundError。
我想添加另一个场景,它也可能导致 NoClassDefFoundError。
当您尝试加载由于静态初始化块中的某些异常而无法加载的类时,系统将抛出 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.<clinit>(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.<clinit>(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。
从Why am I getting a NoClassDefFoundError in Java?找到样本
【讨论】:
【参考方案8】:NoClassDefFoundError 发生的一种情况是在类路径中找不到类 JVM 尝试访问的情况。 但是如果类路径中存在类,则会导致 ClassNotFoundException。
简而言之,如果类在编译期间存在但在运行期间在 java 类路径中不可用,则会出现 NoClassDefFoundError。
尝试在类路径不包含 B 类的情况下使用显式 -classpath 选项运行。
【讨论】:
如果类存在于类路径中,为什么你会得到ClassNotFoundException
?【参考方案9】:
此线程中的其他答案是正确的,我只是想添加一些我花了几个小时试图弄清楚的东西。即使
Class.forName("apache.some.SomeLegitClass")
有效,
Class.forName("apache.some.somelegitclass")
将导致 NoClassDefFoundError。 Class.forName() 区分大小写。如果类名拼写错误,或者只是大小写错误,则会导致不同的异常。
【讨论】:
以上是关于ClassNotFoundException 与 NoClassDefFoundError的主要内容,如果未能解决你的问题,请参考以下文章
Java理解ClassNotFoundException与NoClassDefFoundError的区别
pyspark 与 MariaDB 的连接失败并出现 ClassNotFoundException
ClassNotFoundException: com.auth0.jwt.exceptions.JWTCreationException 与 DocuSignApi Java SDK
将 SafeArgs 与 Proguard 和导航架构组件一起使用时出现 ClassNotFoundException?
java.lang.ClassNotFoundException与java.lang.NoClassDefFoundError的区别