如何解决java.lang.NoClassDefFoundError?


220

我已经尝试了Oracle Java教程中的两个示例。它们都可以正常编译,但是在运行时都出现此错误:

Exception in thread "main" java.lang.NoClassDefFoundError: graphics/shapes/Square
    at Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: graphics.shapes.Square
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    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

我想我可能将Main.java文件放在错误的文件夹中。这是目录层次结构:

graphics
 Main.java
 shapes
|    Square.java
|    Triangle.java
 linepoint
|    Line.java
|    Point.java
 spaceobjects
|    Cube.java
|    RectPrism.java

这里是Main.java

import graphics.shapes.*;
import graphics.linepoint.*
import graphics.spaceobjects.*;

public class Main {
    public static void main(String args[]) {
        Square s = new Square(2,3,15);
        Line l = new Line(1,5,2,3);
        Cube c = new Cube(13,32,22);
    }
}

我在这里做错了什么?

更新

Main类放入graphics包中后(package graphics;将其添加到其中),将类路径设置为“ _test”(包含图形的文件夹),进行编译,然后使用java graphics.Main(从命令行)运行它,就可以了。

真的晚了更新#2

我没有使用Eclipse(只是Notepad ++和JDK),因此上述更新解决了我的问题。但是,似乎许多答案都是针对Eclipse和IntelliJ的,但是它们具有相似的概念。


1
查看您的主类,它不在包中(您将package graphics;在顶部)。是graphics您包装结构的头吗?Square package graphics.shapes在顶部吗?
lreeder

1
您列出的是.java文件的位置,但是由于获取的是运行时问题,因此您真正感兴趣的是.class文件的位置以及它们是否在类路径中。您如何执行Main类?
Thor84no 2013年

只需在月食中按Shift + Ctrl + O即可组织您的进口商品
happybuddha

确保您正确键入类名称。我收到此错误是因为我没有使用大写字母开头课程名称
Jeremy Borg 2014年

在进行重大重构后,有时会在IntelliJ IDEA中发生这种情况。右键单击您的项目,然后选择->编译模块,然后重新启动该项目,它应该可以再次工作。
2014年

Answers:


223

编译代码后,最终将得到.class程序中每个类的文件。这些二进制文件是Java解释为执行程序的字节码。该NoClassDefFoundError指示类加载器(在这种情况下java.net.URLClassLoader),这是负责动态加载类,无法找到.class该类你试图使用的文件。

如果不存在必需的类(除非使用反射加载了类),则您的代码将不会编译,因此通常此异常意味着您的类路径不包含必需的类。请记住,类加载器(特别是java.net.URLClassLoader)将在类路径中每个条目中的文件夹abc中的a / b / c /文件夹中查找类。NoClassDefFoundError也可能表示您缺少编译时要使用的.jar文件的传递依赖项。

例如,如果您有一个类com.example.Foo,则在编译后将有一个类文件Foo.class。假设您的工作目录为.../project/。该类文件必须放在中.../project/com/example,并且您将您的类路径设置为.../project/

旁注:我建议您利用Java和JVM语言中已有的惊人工具。诸如Eclipse和IDEA之类的现代IDE以及诸如Maven或Gradle之类的构建管理工具将帮助您不必担心类路径(太多)而专注于代码!就是说,此链接说明了在命令行执行时如何设置类路径。


我正在阅读本文,是因为尝试在Android上运行单元测试时遇到错误。事实证明,就我而言,NoClassDefFoundError是由于测试中缺少依赖项而发生的。我需要考虑依赖注入,以防止此类错误。感谢详尽的回答。
典型的丹尼

130

我想纠正别人对的看法NoClassDefFoundError

NoClassDefFoundError 可能由于多种原因而发生,例如

  1. ClassNotFoundException-找不到该引用类的.class,无论它在编译时是否可用(即基类/子类)。
  2. 定位类文件,但初始化静态变量时引发异常
  3. 找到类文件,初始化静态块时引发异常

在最初的问题中,这是第一种情况,可以通过将CLASSPATH设置为所引用的类jar文件或其包文件夹来纠正。

说“在编译时可用”是什么意思?

  • 引用的类在代码中使用。
    例如:A和B两类(扩展A)。如果直接在代码中引用B,则它在编译时可用,即A a = new B();。

说“在编译时不可用”是什么意思?

  • 编译时类和运行时类是不同的,例如,使用子类的类名加载基类,例如Class.forName(“ classname”)
    例如:A和B(扩展A)这两个类。代码具有
    A a = Class.forName(“ B”)。newInstance();

就我而言,我已经编译了一个类,他们将其移动到名为app的目录中。我必须先添加一行package app;并重新编译,然后才能将其移动到子目录应用程序中。
塔科

1
除了上面列出的3外,ClassLoaders也可能会导致这种错误,该错误基本上是ClassNotFoundException,在这种情况下,类可能会出现在classpath中,但尝试从其他ClassLoader加载
Fahad

2和3是特定于类加载器的。根据javadoc的规定,该异常仅出于原因
Samuel

1
我已经测试了案例2和案例3,它不是NoClassDefFoundError,它是案例2.Class文件中的ExceptionInInitializerError,但是在初始化静态变量时出现了案例3。在类文件中,在初始化静态块时引发了异常
Michael

1
@Michael,此链接说,在NoClassDefFoundError这种情况下,您的堆栈跟踪也将显示:archive.is/YPbYI#selection-2107.0-2115.13
Pacerier

15

NoClassDefFoundError表示该类存在于的类路径中Compile time,但不存在于的类路径中Runtime

如果你正在使用Eclipse,请确保您有shapeslinepointsspaceobjects作为项目中的.classpath文件。


1
如何在运行时通过try / catch处理呢?
行家ツ

5
这个答案不正确,你写它的方式。正确的是:“此错误的一个可能原因是...。”但是,例如,在使用类加载器在运行时加载JAR文件时,可能会有其他原因导致您收到此错误。
Elmue '17

13

如果在编译和运行时遇到以下错误之一:

* NoClassDefFoundError

* Error: Could not find or load main class hello

* Exception in thread "main" java.lang.NoClassDefFoundError:javaTest/test/hello 
(wrong name: test/hello)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        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)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

-------------------------- 解决方案 -----------------------

问题主要在包装组织中。您应该根据源代码中的软件包分类,在文件夹中正确安排类。

On Compiling process use this command:

javac -d . [FileName.java]

To Run the class please use this command:

java [Package].[ClassName]

“ -d”。在javac命令中可以达到目的,创建包的文件夹结构而不是将所有.class文件放在根目录中,谢谢!
豪尔赫·桑帕约19年

9
java.lang.NoClassDefFoundError

表示在编译找到了某些东西,但在运行时未找到。也许您只需要将其添加到类路径中即可。


15
怎么做?
纳伦德拉·辛格

取决于您要求的上下文。
sschrass '16

6

当在类路径中找不到所需的类时,不会发生任何类定义异常。在编译时类:类是从Java编译器生成的,但是以某种方式在运行时未找到相关类。

让我们看一个简单的例子:

public class ClassA{
public static void main(String args[]){
     //Some gibberish Code...
     String text = ClassB.getString();
     System.out.println("Text is :" + text);
}

}

public class ClassB{
    public static String getString(){
      return "Testing Some Exception";
 }
}

现在,假设将上面的两个Java源代码放置在某个Folder中,并说“ NoClassDefinationFoundExceptionDemo”

现在打开一个shell(假设已经正确设置了Java)

  1. 转到文件夹“ NoClassDefinationFoundExceptionDemo”
  2. 编译Java源文件javac ClassB javac ClassA
  3. 这两个文件都已成功编译,并在与ClassA.class和ClassB.class相同的文件夹中生成了Class文件。
  4. 现在,由于我们将ClassPath覆盖到当前工作目录,因此我们执行以下命令 java -cp。A类 并成功运行,您将在屏幕上看到输出
  5. 现在让我们说,您从Present Directory中删除了ClassB.class文件。现在您再次执行命令。 java -cp。ClassA现在它将以NoClassDefFoundException问候您。因为在类路径(即当前工作目录)中找不到作为类A的依赖项的类B。

5

Java中的NoClassDefFoundError:

定义:

如果一个类在编译期间存在但在运行时在Java类路径中不可用,则将出现NoClassDefFoundError。通常,当您收到NoClassDefFoundError时,将在日志中看到以下行:线程“ main”中的异常java.lang.NoClassDefFoundError

可能的原因:

  1. 该类在Java Classpath中不可用。

  2. 您可能正在使用jar命令运行程序,并且清单文件的ClassPath属性中未定义类。

  3. 任何启动脚本都将覆盖Classpath环境变量。

  4. 由于NoClassDefFoundError是java.lang.LinkageError的子类,因此如果其中一个依赖项(如本机库)可能不可用,它也可能会出现。

  5. 在日志文件中检查java.lang.ExceptionInInitializerError。由于静态初始化失败而导致的NoClassDefFoundError非常普遍。

  6. 如果您在J2EE环境中工作,则多个Classloader之间Class的可见性也可能导致java.lang.NoClassDefFoundError,请参阅示例和场景一节以获取详细讨论。

可能的解决方案:

  1. 验证所有必需的Java类都包含在应用程序的类路径中。最常见的错误是在开始执行依赖于某些外部库的Java应用程序之前,不包括所有必需的类。

  2. 应用程序的类路径是正确的,但是在应用程序执行之前会覆盖Classpath环境变量。

  3. 验证上述ExceptionInInitializerError是否未出现在应用程序的堆栈跟踪中。

资源:

解决Java J2EE中的java.lang.NoClassDefFoundError的3种方法

java.lang.NoClassDefFoundError-如何解决找不到类Def的错误


3

如果您的项目位于包之com.blahcodeMain的文件中,并且您的类被调用,则编译后的文件可能会以的目录结构形式输出./out/com/blahcode/Main.class。对于IntelliJ IDEA尤其如此。

当尝试从shell或cmd运行时,您需要到cd其中包含com作为子目录的目录。

cd out
java -classpath . com.blahcode.Main

1

在NetBeans项目上工作了几个月后,在收到“内存不足”警报后不久,我突然收到NoClassDefFoundError消息。进行Clean重建无济于事,但是完全关闭Netbeans并重新打开项目,没有错误报告。


1

这个答案是特定于服务中发生的java.lang.NoClassDefFoundError的:

我的团队最近在升级提供服务的rpm后看到此错误。rpm及其内部的软件是使用Maven构建的,因此似乎我们有一个编译时相关性,但尚未包含在rpm中。

但是,在调查时,未找到的类与堆栈跟踪中的几个类位于同一模块中。此外,这不是最近才添加到构建中的模块。这些事实表明,这可能不是Maven依赖问题。

最终的解决方案:重新启动服务!

看来rpm升级使基础jar文件上的服务文件句柄无效。然后该服务看到一个尚未加载到内存中的类,在其jar文件句柄列表中搜索该类,但由于可以加载该类的文件句柄已失效而未能找到它。重新启动该服务会强制其重新加载其所有文件句柄,然后允许它加载在rpm升级后立即在内存中找不到的类。

希望具体案例对某人有所帮助。


1

我今天已经面对这个问题。我有一个Android项目,启用multidex该项目后将无法启动。

原因是我忘记了调用特定的multidex方法,该方法应该添加到中Application class并在其他所有方法之前被调用。

 MultiDex.install(this);

按照本教程正确启用multidex。https://developer.android.com/studio/build/multidex.html

您应该将这些行添加到Application类中

 @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }

1

对于我的项目,解决问题的是Chrome浏览器和chromedriver不兼容。我的驱动程序版本太旧,甚至无法打开浏览器。我刚刚下载了两者的最新版本,并解决了问题。我是怎么发现这个问题的?因为我使用Selenium本机firefox驱动程序运行了项目,并且将旧版本的FF与我的应用程序结合在一起,所以我意识到问题出在浏览器和驱动程序之间。

希望这可以帮助产生类似错误消息的任何人,如我的类似问题。


0

我在这条链上的两分钱:

确保classpath包含完整路径(/home/user/lib/some_lib.jar而不是~/lib/some_lib.jar),否则您仍然会遇到NoClassDefFoundError错误。


这部分是正确的,但更为复杂。1)您可以在类路径中使用相对路径,但是相对于JVM当前目录,它们必须是可被JVM ...解析的。这使它们易碎。2)设置类路径环境变量时,可以使用~和其他shell元字符,但前提是要使用用于设置变量的机制将它们扩展为真实路径名。如果使用bash,则可以得到“混合”结果。例如,查看在echo ~:~命令行上键入时得到的内容。第一个~被扩展,但是第二个则没有。
斯蒂芬·C

0

当运行时类加载器加载的类无法访问java rootloader已加载的类时,出现NoClassFoundError。由于不同的类加载器位于不同的安全域中(根据Java),因此jvm不允许在运行时加载器地址空间中解析由根加载器加载的类。

使用“ java -javaagent:tracer.jar [您的Java插件]”运行程序

它产生的输出显示已加载的类,以及加载该类的加载器env。跟踪为什么无法解析类非常有用。

// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5

import java.lang.instrument.*;
import java.security.*;

// manifest.mf
// Premain-Class: ClassLoadTracer

// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class

// java -javaagent:tracer.jar  [...]

public class ClassLoadTracer 
{
    public static void premain(String agentArgs, Instrumentation inst) 
    {
        final java.io.PrintStream out = System.out;
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

                String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
                out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);

                // dump stack trace of the thread loading class 
                Thread.dumpStack();

                // we just want the original .class bytes to be loaded!
                // we are not instrumenting it...
                return null;
            }
        });
    }
}

0

这在Android Studio中发生在我身上。

对我有用的解决方案:只需重新启动Studio。


0

使用Android Studio进行Android开发时,我遇到了同样的问题。提供的解决方案是一般性的,对我没有帮助(至少对我而言)。经过数小时的研究,我发现了以下解决方案,可能会对正在使用android studio进行开发的android开发人员有所帮助。修改以下设置,如下所示:首选项->构建,执行,部署->即时运行->取消选中第一个选项。

有了这个更改,我就可以运行了。希望这对我的开发者朋友有帮助。


0

该异常的一个错误来源可能是Proguard的定义不一致,例如缺少

-libraryJars“缺少的jar的路径”。

这就解释了为什么在存在jar的情况下进行编译和运行都能正常进行,而clean&build却失败了。记住要在proguard设置中定义新添加的jar库!

请注意,来自Proguard的错误消息确实不符合标准,因为它们很容易与罐子根本不在时到达的类似蚂蚁消息混淆。只有在最底层,才会有一小撮拥护者陷入困境。因此,开始搜索传统的类路径错误等是很合逻辑的,但这是徒劳的。

显然,NoClassDefFound异常将是运行时的结果,例如,由于缺少proguard一致性而生成的可执行jar。有人称它为“地狱”


0

我使用了适用于EclipseFileSync插件,因此可以在Tomcat上进行实时调试,并且收到了此消息,NoClassFoundError因为我已经在Tomcat bin的Eclipse工作区=> classes中为该目录添加了一个同步条目,metadata但是没有extlib在Eclipse中为该目录添加了文件夹同步=>

C:\Users\Stuart\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps\myApp\WEB-INF\lib


0

我正在开发基于Eclipse的应用程序,也称为RCP(Rich Client Platform)。。重构后(将一个类从一个插件移动到一个新的类),我一直面临着这个问题。

清理项目和Maven更新无济于事。

该问题是由尚未自动更新的Bundle-Activator引起的。在新插件中的MANIFEST.MF下手动更新Bundle-Activator 修复了我的问题。


0

如果您最近在android studio中添加了对multidex的支持,例如:

// To Support MultiDex
implementation 'com.android.support:multidex:1.0.1'

所以您的解决方案只是从MultiDexApplication而不是Application扩展而来

public class MyApp extends MultiDexApplication {


0

检查类中是否有静态处理程序。如果是这样,请小心,因为只能在具有循环程序的线程中启动静态处理程序,才可以通过以下方式触发崩溃:

1.首先,在一个简单的线程中创建类的实例并捕获崩溃。

2.然后在主线程中调用Class的字段方法,将得到NoClassDefFoundError。

这是测试代码:

public class MyClass{
       private static  Handler mHandler = new Handler();
       public static int num = 0;
}

在您的Main活动的onCrete方法中,添加测试代码部分:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //test code start
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                MyClass myClass = new MyClass();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }).start();

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    MyClass.num = 3;
    // end of test code
}

有一种使用handlerThread来初始化处理程序的简单方法:

private static Handler mHandler;
private static HandlerThread handlerThread = new HandlerThread("newthread");
static {
    handlerThread.start();
    mHandler = new Handler(handlerThread.getLooper(), mHandlerCB);
}

0

不要在模块外使用测试类

我没有解决方案,只是“编译时存在,运行时不存在”情况的另一种形式。

我试图使用JUnit测试类中一个非常方便的方法,该方法来自另一个测试类,该类位于另一个模块中。这是不可以的,因为测试代码不是打包的jar的一部分,但是我没有意识到,因为它对于Eclipse中的用户类而言是可见的。

我的解决方案是将方法放在生产代码中现有的实用程序类中。


0

在我的环境中,我在单元测试中遇到此问题。将一个库依赖项附加到* .pom后,此问题已解决。

例如:

错误信息:

java.lang.NoClassDefFoundError: com/abc/def/foo/xyz/Iottt

pom:

<dependency>
    <groupId>com.abc.def</groupId>
    <artifactId>foo</artifactId>
    <scope>test</scope>
</dependency>

0

Git分支更改后出现此错误。对于Eclipse的特定情况,org.eclipse.wst.common.component文件的.settings目录中缺少行。如您所见

使用Maven Install恢复项目依赖关系会有所帮助。

在此处输入图片说明


-1

我的genymotion设备经常发生这种情况。确保安装了Genymotion的驱动器上有足够的可用内存。


您对此有参考吗?
威哈李

是的,我只是经常用尽磁盘空间,除非我释放大量+删除/重新安装Genymotion虚拟设备,否则我会不断收到此错误。
totteire
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.