Java NoClassDefFoundError 和 ClassNotFoundException 的原因和区别是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1457863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:28:37  来源:igfitidea点击:

What causes and what are the differences between NoClassDefFoundError and ClassNotFoundException?

javaclasspathnoclassdeffounderrorclassnotfoundexception

提问by krisp

What is the difference between NoClassDefFoundErrorand ClassNotFoundException?

NoClassDefFoundError和 和有ClassNotFoundException什么区别?

What causes them to be thrown? How can they be resolved?

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

I often encounter these throwables when modifying existing code to include new jar files. I have hit them on both the client side and the server side for a java app distributed through webstart.

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

Possible reasons I have come across:

我遇到的可能原因:

  1. packages not included in build.xmlfor the client side of code
  2. runtime classpath missing for the new jars we are using
  3. version conflicts with previous jar
  1. 未包含在build.xml代码客户端的包
  2. 我们正在使用的新 jar 缺少运行时类路径
  3. 版本与之前的 jar 冲突

When I encounter these today I take a trail-and-error approach to get things working. I need more clarity and understanding.

当我今天遇到这些时,我会采取跟踪错误的方法来使事情正常进行。我需要更多的清晰度和理解力。

采纳答案by coobird

The difference from the Java API Specifications is as follows.

与 Java API 规范的区别如下。

For ClassNotFoundException:

对于ClassNotFoundException

Thrown when an application tries to load in a class through its string name using:

  • The forNamemethod in class Class.
  • The findSystemClassmethod in class ClassLoader.
  • The loadClassmethod in class ClassLoader.

but no definition for the class with the specified name could be found.

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

  • forName类中的方法Class
  • findSystemClass类中的方法ClassLoader
  • loadClass类中的方法ClassLoader

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

For NoClassDefFoundError:

对于NoClassDefFoundError

Thrown if the Java Virtual Machine or a ClassLoaderinstance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.

The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

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

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

So, it appears that the NoClassDefFoundErroroccurs when the source was successfully compiled, but at runtime, the required classfiles were not found. This may be something that can happen in the distribution or production of JAR files, where not all the required classfiles were included.

所以,看起来是在NoClassDefFoundError源代码编译成功时发生的,但在运行时,class找不到所需的文件。这可能会发生在 JAR 文件的分发或生产中,其中并未class包含所有必需的文件。

As for ClassNotFoundException, it appears that it may stem from trying to make reflective calls to classes at runtime, but the classes the program is trying to call is does not exist.

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

The difference between the two is that one is an Errorand the other is an Exception. With NoClassDefFoundErroris an Errorand it arises from the Java Virtual Machine having problems finding a class it expected to find. A program that was expected to work at compile-time can't run because of classfiles not being found, or is not the same as was produced or encountered at compile-time. This is a pretty critical error, as the program cannot be initiated by the JVM.

两者的区别在于一个是an Error,另一个是an Exception。随着NoClassDefFoundErrorError,它源于其发现的一类,它预计到发现问题的Java虚拟机。预期在编译时工作的程序由于class找不到文件而无法运行,或者与编译时生成或遇到的文件不同。这是一个非常严重的错误,因为程序无法由 JVM 启动。

On the other hand, the ClassNotFoundExceptionis an Exception, so it is somewhat expected, and is something that is recoverable. Using reflection is can be error-prone (as there is some expectations that things may not go as expected. There is no compile-time check to see that all the required classes exist, so any problems with finding the desired classes will appear at runtime.

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

回答by cletus

NoClassDefFoundErroris a linkage error basically. It occurs when you try and instantiate an object (statically with "new") and it's not found when it was during compilation.

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

ClassNotFoundExceptionis more general and is a runtime exception when you try to use a class that doesn't exist. For example, you have a parameter in a function accepts an interface and someone passes in a class that implements that interface but you don't have access to the class. It also covers case of dynamic class loading, such as using loadClass()or Class.forName().

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

回答by Vineet Reynolds

ClassNotFoundExceptionis thrown when there is attempt to load the class by referencing it via a String. For example the parameter to in Class.forName() is a String, and this raises the potential of invalid binary names being passed to the classloader.

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

The ClassNotFoundException is thrown when a potentially invalid binary name is encountered; for instance, if the class name has the '/' character, you are bound to get a ClassNotFoundException. It is also thrown when the directly referenced class is not available on the classpath.

当遇到潜在无效的二进制名称时抛出 ClassNotFoundException;例如,如果类名有“/”字符,你一定会得到一个 ClassNotFoundException。当直接引用的类在类路径上不可用时,它也会被抛出。

On the other hand, NoClassDefFoundErroris thrown

另一方面,抛出NoClassDefFoundError

  • when the actual physical representation of the class - the .class file is unavailable,
  • or the class been loaded already in a different classloader (usually a parent classloader would have loaded the class and hence the class cannot be loaded again),
  • or if an incompatible class definition has been found - the name in the class file does not match the requested name,
  • or (most importantly) if a dependent class cannot be located and loaded. In this case, the directly referenced class might have been located and loaded, but the dependent class is not available or cannot be loaded. This is a scenario where the directly referenced class can be loaded via a Class.forName or equivalent methods. This indicates a failure in linkage.
  • 当类的实际物理表示 - .class 文件不可用时,
  • 或者该类已经在不同的类加载器中加载(通常父类加载器会加载该类,因此无法再次加载该类),
  • 或者如果发现了不兼容的类定义 - 类文件中的名称与请求的名称不匹配,
  • 或者(最重要的是)如果无法定位和加载依赖类。在这种情况下,可能已经找到并加载了直接引用的类,但依赖类不可用或无法加载。在这种情况下,可以通过 Class.forName 或等效方法加载直接引用的类。这表示链接失败。

In short, a NoClassDefFoundError is usually thrown on new() statements or method invocations that load a previously absent class (as opposed to the string-based loading of classes for ClassNotFoundException), when the classloader is unable to find or load the class definition(s).

简而言之,当类加载器无法找到或加载类定义( s)。

Eventually, it is upto the ClassLoader implementation to throw an instance of ClassNotFoundException when it is unable to load a class. Most custom classloader implementations perform this since they extend the URLClassLoader. Usually classloaders do not explicitly throw a NoClassDefFoundError on any of the method implementations - this exception is usually thrown from the JVM in the HotSpot compiler, and not by the classloader itself.

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

回答by Sanjiv Jivan

A ClassNotFoundException is thrown when the reported class is not found by the ClassLoader. This typically means that the class is missing from the CLASSPATH. It could also mean that the class in question is trying to be loaded from another class which was loaded in a parent classloader and hence the class from the child classloader is not visible. This is sometimes the case when working in more complex environments like an App Server (WebSphere is infamous for such classloader issues).

当 ClassLoader 找不到报告的类时,会抛出 ClassNotFoundException。这通常意味着 CLASSPATH 中缺少该类。这也可能意味着有问题的类正试图从另一个类加载到父类加载器中,因此子类加载器中的类不可见。在应用服务器等更复杂的环境中工作时,有时会出现这种情况(WebSphere 因此类加载器问题而臭名昭著)。

People often tend to confuse java.lang.NoClassDefFoundErrorwith java.lang.ClassNotFoundExceptionhowever there's an important distinction. For example an exception (an error really since java.lang.NoClassDefFoundErroris a subclass of java.lang.Error) like

人们往往容易混淆java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException但有一个重要的区别。例如一个异常(实际上java.lang.NoClassDefFoundError是一个错误,因为它是 java.lang.Error 的一个子类),比如

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

does not mean that the ActiveMQConnectionFactory class is not in the CLASSPATH. Infact its quite the opposite. It means that the class ActiveMQConnectionFactory was found by the ClassLoader however when trying to load the class, it ran into an error reading the class definition. This typically happens when the class in question has static blocks or members which use a Class that's not found by the ClassLoader. So to find the culprit, view the source of the class in question (ActiveMQConnectionFactory in this case) and look for code using static blocks or static members. If you don't have access the the source, then simply decompile it using JAD.

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

On examining the code, say you find a line of code like below, make sure that the class SomeClass in in your CLASSPATH.

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

private static SomeClass foo = new SomeClass();

Tip : To find out which jar a class belongs to, you can use the web site jarFinder . This allows you to specify a class name using wildcards and it searches for the class in its database of jars. jarhoo allows you to do the same thing but its no longer free to use.

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

If you would like to locate the which jar a class belongs to in a local path, you can use a utility like jarscan ( http://www.inetfeedback.com/jarscan/). You just specify the class you'd like to locate and the root directory path where you'd like it to start searching for the class in jars and zip files.

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

回答by mogsie

A NoClassDefFoundError (NCDFE) happens when your code runs "new Y()" and it can't find the Y class.

NoClassDefFoundError (NCDFE) 在您的代码运行“new Y()”并且找不到 Y 类时发生。

It may simply be that Y is missing from your class loader like the other comments suggest, but it could be that the Y class isn't signed or has an invalid signature, or that Y is loaded by a different classloader not visible to your code, or even that Y depends on Z which couldn't be loaded for any of the above reasons.

可能只是像其他评论建议的那样,您的类加载器中缺少 Y,但也可能是 Y 类未签名或具有无效签名,或者 Y 是由您的代码不可见的其他类加载器加载的,甚至 Y 依赖于 Z ,由于上述任何原因而无法加载。

If this happens, then the JVM will remember the result of loading X (NCDFE) and it will simply throw a new NCDFE every time you ask for Y without telling you why:

如果发生这种情况,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();}
  }
}

save this as a.java somewhere

将其保存为 a.java 某处

The code simply tries to instantiate a new "b" class twice, other than that, it doesn't have any bugs, and it doesn't do anything.

代码只是尝试两次实例化一个新的“b”类,除此之外,它没有任何错误,也没有做任何事情。

Compile the code with javac a.java, Then run a by invoking java -cp . a-- it should just print out two lines of text, and it should run fine without errors.

使用 编译代码javac a.java,然后通过调用运行 a java -cp . a—— 它应该只打印出两行文本,并且应该可以正常运行而不会出错。

Then delete the "a$b.class" file (or fill it with garbage, or copy a.class over it) to simulate the missing or corrupted class. Here's what happens:

然后删除“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.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)

The first invocation results in a ClassNotFoundException (thrown by the class loader when it can't find the class), which must be wrapped in an unchecked NoClassDefFoundError, since the code in question (new b()) should just work.

第一次调用导致 ClassNotFoundException(当它找不到类时由类加载器抛出),它必须包含在一个未经检查的 NoClassDefFoundError 中,因为有问题的代码 ( new b()) 应该可以正常工作。

The second attempt will of course fail too, but as you can see the wrapped exception is no more, because the ClassLoader seems to remember failed class loaders. You see only the NCDFE with absolutely no clue as to what really happened.

第二次尝试当然也会失败,但是正如您所看到的,包装的异常不再存在,因为 ClassLoader 似乎记住了失败的类加载器。你只看到 NCDFE,完全不知道到底发生了什么。

So if you ever see a NCDFE with no root cause, you need to see if you can track back to the very first time the class was loaded to find the cause of the error.

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

回答by Donal Fellows

What is the reason for getting each of them and any thought process on how to deal with such errors?

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

They're closely related. A ClassNotFoundExceptionis thrown when Java went looking for a particular class by name and could not successfully load it. A NoClassDefFoundErroris thrown when Java went looking for a class that was linked into some existing code, but couldn't find it for one reason or another (e.g., wrong classpath, wrong version of Java, wrong version of a library) and is thoroughly fatal as it indicates that something has gone Badly Wrong.

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

If you've got a C background, a CNFE is like a failure to dlopen()/dlsym()and an NCDFE is a problem with the linker; in the second case, the class files concerned should never have been actually compiled in the configuration you're trying to use them.

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

回答by leef

Add one possible reason in practise:

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

  • ClassNotFoundException: as cletus said, you use interface while inherited class of interface is not in the classpath. E.g, Service Provider Pattern (or Service Locator) try to locate some non-existing class
  • NoClassDefFoundError: given class is found while the dependency of given class is not found
  • ClassNotFoundException:正如cletus所说,您使用接口,而继承的接口类不在类路径中。例如,服务提供者模式(或服务定位器)尝试定位一些不存在的类
  • NoClassDefFoundError:找到给定的类,而未找到给定类的依赖项

In practise, Errormay be thrown silently, e.g, you submit a timer task and in the timer task it throws Error, while in most cases, your program only catches Exception. Then the Timermain loop is ended without any information. A similar Error to NoClassDefFoundError is ExceptionInInitializerError, when your static initializer or the initializer for a static variable throws an exception.

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

回答by KingFeming

From http://www.javaroots.com/2013/02/classnotfoundexception-vs.html:

来自http://www.javaroots.com/2013/02/classnotfoundexception-vs.html

ClassNotFoundException: occurs when class loader could not find the required class in class path. So, basically you should check your class path and add the class in the classpath.

ClassNotFoundException: 当类加载器在类路径中找不到所需的类时发生。所以,基本上你应该检查你的类路径并将类添加到类路径中。

NoClassDefFoundError: this is more difficult to debug and find the reason. This is thrown when at compile time the required classes are present, but at run time the classes are changed or removed or class's static initializes threw exceptions. It means the class which is getting loaded is present in classpath, but one of the classes which are required by this class are either removed or failed to load by compiler. So you should see the classes which are dependent on this class.

NoClassDefFoundError: 这个比较难调试,找原因。当在编译时存在所需的类时会抛出此问题,但在运行时类被更改或删除或类的静态初始化抛出异常。这意味着正在加载的类存在于类路径中,但此类所需的类之一已被删除或无法被编译器加载。所以你应该看到依赖这个类的类。

Example:

示例

public class Test1
{
}


public class Test 
{
   public static void main(String[] args)
   {
        Test1 = new Test1();    
   }

}

Now after compiling both the classes, if you delete Test1.class file and run Test class, it will throw

现在在编译这两个类之后,如果删除 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.run(Unknown Source)
    at java.net.URLClassLoader.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: thrown when an application tries to load in a class through its name, but no definition for the class with the specified name could be found.

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

NoClassDefFoundError: thrown if the Java Virtual Machine tries to load in the definition of a class and no definition of the class could be found.

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

回答by Dinesh

Example #1:

示例#1:

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}

If com/example/Class1doesn't exist in any of the classpaths, then It throws ClassNotFoundException.

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

Example #2:

示例#2:

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}

If com/example/Class2existed while compiling B, but not found while execution, then It throws NoClassDefFoundError.

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

Both are run time exceptions.

两者都是运行时异常。

回答by Anton Shchastnyi

Given the Class loader sussystem actions:

鉴于类加载器 sussystem 操作:

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

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

This is an article that helped me a lot to understand the difference: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

这是一篇对我理解差异有很大帮助的文章:http: //docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

If an error occurs during class loading, then an instance of a subclass of LinkageErrormust be thrown at a point in the program that (directly or indirectly) uses the class or interface being loaded.

If the Java Virtual Machine ever attempts to load a class C during verification (§5.4.1) or resolution (§5.4.3) (but not initialization (§5.5)), and the class loader that is used to initiate loading of C throws an instance of ClassNotFoundException, then the Java Virtual Machine must throw an instance of NoClassDefFoundErrorwhose cause is the instance of ClassNotFoundException.

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

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

So a ClassNotFoundExceptionis a root cause of NoClassDefFoundError.
And a NoClassDefFoundErroris a special case of type loading error, that occurs at Linkingstep.

所以ClassNotFoundExceptionNoClassDefFoundError的根本原因。
而一个NoClassDefFoundError的是类加载错误的特殊情况下,发生在链接的一步。