首页 文章

如何解决java.lang.NoClassDefFoundError?

提问于
浏览
169

我've tried both the example in Oracle' s Java Tutorials . 它们都编译得很好,但在运行时,都会出现这个错误:

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);
    }
}

我在这做错了什么?

UPDATE

在我把 Main 类放入 graphics 包(我添加了 package graphics; )后,将类路径设置为"_test"(包含图形的文件夹),编译它,并使用 java graphics.Main (从命令行)运行它,它工作 .

Really late UPDATE #2

我没有使用Eclipse(只是Notepad和JDK),上面的更新解决了我的问题 . 但是,似乎许多这些答案都适用于Eclipse和IntelliJ,但它们具有相似的概念 .

22 回答

  • 104

    编译代码后,最终会为程序中的每个类生成 .class 个文件 . 这些二进制文件是Java解释执行程序的字节码 . NoClassDefFoundError 表示负责动态加载类的类加载器(在本例中为 java.net.URLClassLoader )无法找到您尝试使用的类的 .class 文件 .

    您的代码不会出现(除非使用反射加载类),因此通常此异常意味着您的类路径不包含所需的类 . 请记住,类加载器(特别是 java.net.URLClassLoader )将在类路径的每个条目中的文件夹a / b / c /中查找包a.b.c中的类 . NoClassDefFoundError 也可以表示您编译了're missing a transitive dependency of a .jar file that you',并且您正在尝试使用 .

    例如,如果您有一个类 com.example.Foo ,则在编译之后您将拥有一个类文件 Foo.class . 比如说你的工作目录是 .../project/ . 该类文件必须放在 .../project/com/example 中,您可以将类路径设置为 .../project/ .

    旁注:我建议利用Java和JVM语言中存在的神奇工具 . 现代IDE就像Eclipse和IDEA以及构建管理工具(如Maven或Gradle)将帮助您不必担心类路径(尽可能多)并专注于代码!也就是说,this link解释了在命令行上执行时如何设置类路径 .

  • 12

    我想在 NoClassDefFoundError 上纠正别人的观点 .

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

    • ClassNotFoundException - 找不到该引用类的.class,无论它是否在编译时可用(即base / child class) .

    • 找到类文件,但在初始化静态变量时引发了异常

    • 找到类文件,初始化静态块时引发异常

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

    说"available in compile time"是什么意思?

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

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

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

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

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

  • 0

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

    * 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)
    

    -------------------------- SOLUTIION -----------------------

    the problem is mostly in packages organization. You should arrange your classes in folders properly regarding to the package classifications in your source code.

    On Compiling process use this command:
    
    javac -d . [FileName.java]
    
    To Run the class please use this command:
    
    java [Package].[ClassName]
    
  • 0
    java.lang.NoClassDefFoundError
    

    表示在编译时发现了某些内容但在运行时未发现 . 也许你只需要将它添加到类路径中 .

  • 8

    当在类路径中找不到目标类时,会出现 No Class Definition Exception . 在编译时类:从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源代码放在一些文件夹中,让我们说“NoClassDefinationFoundExceptionDemo”

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

    • 转到文件夹"NoClassDefinationFoundExceptionDemo"

    • 编译Java源文件javac ClassB javac ClassA

    • 两个文件都是成功编译的,并且在与ClassA.class和ClassB.class相同的文件夹中生成了类文件

    • 现在由于我们将ClassPath重写为当前工作目录,因此我们执行以下命令 java -cp . ClassA 并且它成功运行,您将在屏幕上看到输出

    • 现在让我们说,您从Present Directory中删除了ClassB.class文件 . 现在你再次执行命令 . java -cp . ClassA 现在它会用NoClassDefFoundException来迎接你 . 因为在类路径(即当前工作目录)中找不到作为ClassA依赖关系的ClassB .

  • 2

    如果您的项目位于 com.blahcode 之类的包中,并且您的类名为 Main ,则编译的文件可能会在 ./out/com/blahcode/Main.class 之类的目录结构中输出 . 对于IntelliJ IDEA尤其如此 .

    尝试从shell或cmd运行时,需要 cd 到包含 com 的子目录 .

    cd out
    java -classpath . com.blahcode.Main
    
  • 0

    NoClassDefFoundError in Java:

    Definition:

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

    Possible Causes:

    • 该类在Java Classpath中不可用 .

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

    • 任何启动脚本都会覆盖Classpath环境变量 .

    • 因为NoClassDefFoundError是java.lang.LinkageError的子类,所以如果其中一个依赖项(如本机库)可能不可用,也会出现这种情况 .

    • 检查日志文件中的java.lang.ExceptionInInitializerError . 由于静态初始化失败而导致的NoClassDefFoundError非常常见 .

    • 如果您在J2EE环境中工作,那么多个Classloader中的Class的可见性也会导致java.lang.NoClassDefFoundError,请参阅示例和场景部分进行详细讨论 .

    Possible Resolutions:

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

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

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

    Resources:

    3 ways to solve java.lang.NoClassDefFoundError in Java J2EE

    java.lang.NoClassDefFoundError – How to solve No Class Def Found Error

  • 0

    我今天遇到了这个问题 . 我有一个Android项目,启用 multidex 后,项目将不再启动 .

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

    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);
      }
    
  • 0

    在处理NetBeans项目数月后,我在收到“低内存”警报后不久就突然收到NoClassDefFoundError消息 . 做一个干净的重建没有帮助,但完全关闭Netbeans并重新打开项目没有错误报告 .

  • 6

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

    我的团队最近在升级提供服务的rpm后看到了这个错误 . rpm和它内部的软件都是用Maven构建的,所以我们似乎有一个编译时依赖项,而这个依赖项还没有包含在rpm中 .

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

    最终的解决方案: Restart the service!

    似乎rpm升级使基础jar文件上的服务文件句柄无效 . 然后,该服务看到一个尚未加载到内存中的类,在其jar文件句柄列表中搜索它,并且找不到它,因为它可以加载类的文件句柄已经失效 . 重新启动服务会强制它重新加载所有文件句柄,然后允许它在rpm升级后加载那个在内存中找不到的类 .

    希望具体案例有助于某人 .

  • 2

    我在这个链中的两分钱:

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

  • 1

    当运行时类加载器加载的类无法访问java rootloader已经加载的类时,我得到NoClassFoundError . 因为不同的类加载器位于不同的安全域中(根据java),jvm将不允许在运行时加载器地址空间中解析已由rootloader加载的类 .

    用'java -javaagent:tracer.jar [你的java ARGS]'运行你的程序

    它生成显示已加载类的输出,以及加载类的加载器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

    我的genymotion设备发生了很多事情 . 确保安装了Genymotion的驱动器上有足够的可用内存 .

  • 2

    它发生在我的Android Studio中 .

    对我有用的解决方案:重启工作室 .

  • 0

    使用Android studio进行Android开发时遇到了同样的问题 . 提供的解决方案是一般的,并没有帮助我(至少对我来说) . 经过几个小时的研究后,我找到了以下解决方案,可能对使用android studio进行开发的android开发人员有所帮助 . 修改设置,如下面的首选项 - >构建,执行,部署 - >即时运行 - >取消选中第一个选项 .

    有了这个改变,我就开始了 . 希望这能帮助我的开发朋友 .

  • 0

    此异常的一个错误来源可能源于Proguard的定义不一致,例如:一个失踪

    -libraryJars“path.to.a.missing.jar.library” .

    这解释了为什么编译和运行工作正常,因为jar在那里,而clean和build失败 . 记得在proguard设置中定义新添加的jar库!

    请注意,来自Proguard的错误消息实际上不符合标准,因为它们很容易与 jar 根本不存在时到达的类似 Ant 消息混淆 . 只有在最底层才会出现一些麻烦的提示 . 因此,开始搜索传统的类路径错误等是非常逻辑的,但这将是徒劳的 .

    显然,NoClassDefFound异常将是运行时的结果,例如生成的可执行jar是基于缺乏proguard一致性而构建的 . 有人称之为“地狱”

  • 1

    我使用FileSync plugin for Eclipse所以我可以在Tomcat上进行调试并收到了 NoClassFoundError ,因为我已经在 metadata 中的Eclipse工作区 => classes 中为 bin 目录添加了一个同步条目,但是还没有为 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 引起的,它没有自动更新 . 在新的PlugIn中手动更新 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 {
    
  • 178

    如果您使用多个模块,则应该使用

    dexOptions {
        preDexLibraries = false
    }
    

    在您的构建文件中 .

  • 0

    如果您的 class 中有静态处理程序,请检查如果是这样,请小心,因为静态处理程序只能在具有looper的线程中启动,崩溃可以通过这种方式触发:

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

    2.然后在主线程中调用Class的field方法,你将获得NoClassDefFoundError .

    这是测试代码:

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

    在主要活动的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到init处理程序:

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

相关问题