繁体   English   中英

如何解决“java.lang.NoClassDefFoundError”?

[英]How can I solve "java.lang.NoClassDefFoundError"?

我已经尝试了 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);
    }
}

我在这里做错了什么?

更新

After I put put the Main class into the graphics package (I added package graphics; to it), set the classpath to "_test" (folder containing graphics), compiled it, and ran it using java graphics.Main (from the command line ), 有效。

真的很晚更新#2

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

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

如果所需的类不存在,您的代码将无法编译(除非使用反射加载类),因此通常此异常意味着您的类路径不包含所需的类。 请记住,类加载器(特别是java.net.URLClassLoader )将在类路径中每个条目的文件夹 a/b/c/ 中的包 abc 中查找类。 NoClassDefFoundError还可能表明您缺少已编译的 .jar 文件的传递依赖项,并且您正尝试使用该文件。

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

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

我想纠正其他人对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();

NoClassDefFoundError意味着该类在Compile time存在于类路径中,但在Runtime类路径中不存在。

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

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

  • NoClassDefFoundError

  • 错误:无法找到或加载主类 hello

  • 线程“main”中的异常 java.lang.NoClassDefFoundError:javaTest/test/hello(错误名称: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)

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

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

在编译过程中,使用以下命令:

javac -d . [FileName.java]

要运行该类,请使用以下命令:

java [Package].[ClassName]
java.lang.NoClassDefFoundError

表示在编译时找到了某些东西,但在运行时没有找到。 也许你只需要将它添加到类路径中。

当在类路径中找不到预期的类时,会发生无类定义异常

在编译时类:类是从 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 已经正确设置)

  1. 转到文件夹“NoClassDefinationFoundExceptionDemo”

  2. 编译Java源文件 javac ClassB javac ClassA

  3. 两个文件都编译成功,生成的class文件与ClassA.class和ClassB.class在同一个文件夹

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

  5. 现在假设您从当前目录中删除了 ClassB.class 文件。 现在您再次执行该命令。 爪哇 -cp 。 ClassA现在它会用 NoClassDefFoundException 来迎接你。 因为在类路径(即当前工作目录)中找不到作为 ClassA 依赖项的 ClassB。

Java 中的 NoClassDefFoundError:

定义:

NoClassDefFoundError 如果一个类在编译时存在但在运行时在 java 类路径中不可用,则会出现 NoClassDefFoundError。 通常,当您收到 NoClassDefFoundError: Exception in thread "main" java.lang.NoClassDefFoundError 时,您会在日志中看到以下行

可能的原因:

  1. 该类在 Java 类路径中不可用。

  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. 应用程序的类路径是正确的,但在应用程序执行之前,类路径环境变量被覆盖。

  3. 验证上述 ExceptionInInitializerError 没有出现在您的应用程序的堆栈跟踪中。

资源:

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

java.lang.NoClassDefFoundError – 如何解决 No Class Def Found 错误

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

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

cd out
java -classpath . com.blahcode.Main

在 NetBeans 项目上工作数月后,我在收到“内存不足”警报后不久突然收到 NoClassDefFoundError 消息。 进行干净的重建并没有帮助,但是完全关闭 NetBeans 并重新打开项目没有错误报告。

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

我的团队最近在升级提供服务的 rpm 后看到了这个错误。 rpm 和其中的软件是用 Maven 构建的,所以看起来我们有一个编译时依赖,它没有包含在 rpm 中。

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

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

看起来 rpm 升级使底层 JAR 文件上的服务文件句柄无效。 该服务随后看到一个尚未加载到内存中的类,在其 jar 文件句柄列表中搜索它,但未能找到它,因为它可以从中加载该类的文件句柄已失效。 重新启动服务迫使它重新加载所有文件句柄,然后允许它加载在 rpm 升级后在内存中没有找到的那个类。

我今天遇到了这个问题。 我有一个 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);
  }

对于我的项目,解决问题的是 Chrome 浏览器和 chromedriver 不兼容。 我有一个非常旧版本的驱动程序,甚至无法打开浏览器。 我刚刚下载了两者的最新版本,问题解决了。

我是如何发现问题的? 因为我使用 Selenium 本机 Firefox 驱动程序和我的应用程序中包含的旧版本 FF 来运行我的项目。 我意识到问题是浏览器和驱动程序之间的不兼容。

希望这可以帮助任何与我有类似问题的人,这些问题生成了相同的错误消息。

如果您从 JAR 文件“启动”一个类,请确保以 JAR 完整路径开始。 例如,(如果您的“主类”未在清单中指定):

java -classpath "./dialer.jar" com.company.dialer.DialerServer

并且如果有任何依赖,比如对其他JAR文件的依赖,可以解决这样的依赖

  • 通过将此类 JAR 文件(每个 JAR 文件的完整路径)添加到类路径。 例如,
java -classpath "./libs/phone.jar;./libs/anotherlib.jar;./dialer.jar" com.company.dialer.DialerServer
  • 或者通过向清单添加“依赖 JAR 文件”来编辑 JAR 清单。 这样的清单文件可能如下所示:
Manifest-Version: 1.0
Class-Path: phone.jar anotherlib.jar
Build-Jdk-Spec: 1.8
Main-Class: com.company.dialer.DialerServer
  • 或者(如果您是拥有源代码的开发人员)您可以使用 Maven 通过添加到 *.pom 文件来为您准备清单:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>com.company.dialer.DialerServer</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

请注意,上面的示例使用; 作为类路径中的分隔符(它对 Windows 平台有效)。 在 Linux 上,替换; 作者:

例如,

java -classpath ./libs/phone.jar:./libs/anotherlib.jar:./dialer.jar
com.company.dialer.DialerServer

我在使用 Android Studio 进行 Android 开发时遇到了同样的问题。 提供的解决方案是通用的,对我没有帮助(至少对我而言)。

经过数小时的研究,我找到了以下解决方案,它可能对使用 Android Studio 进行开发的 Android 开发人员有所帮助。

修改设置如下:

首选项构建、执行、部署即时运行→ *取消选中第一个选项。

有了这个改变,我就可以开始运行了。

如果你使用多个模块,你应该有

dexOptions {
    preDexLibraries = false
}

在您的构建文件中。

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

清理项目和 Maven 更新没有帮助。

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

我在这条链中的两分钱:

确保类路径包含完整路径( /home/user/lib/some_lib.jar而不是~/lib/some_lib.jar )否则您仍然可能面临NoClassDefFoundError错误。

当运行时类加载器加载的类无法访问 Java 根加载器已加载的类时,我会收到 NoClassFoundError。 因为不同的类加载器在不同的安全域中(根据 Java),JVM 不允许在运行时加载器地址空间中解析根加载器已经加载的类。

使用 'java -javaagent:tracer.jar [YOUR 'java' ARGUMENTS]' 运行您的程序

它产生的输出显示加载的类,以及加载类的加载器环境。 跟踪无法解析类的原因非常有用。

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

它发生在我的Android Studio 中

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

检查您的班级中是否有静态处理程序。 如果是这样,请小心,因为静态处理程序只能在具有循环程序的线程中启动,因此可能会以这种方式触发崩溃:

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

  2. 然后在主线程调用Class的field方法,会得到NoClassDefFoundError。

下面是测试代码:

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

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

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

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

-libraryJars "path.to.a.missing.jar.library"。

这解释了为什么编译和运行工作正常,因为 JAR 文件在那里,而 clean 和 build 失败。 请记住在 ProGuard 设置中定义新添加的 JAR 库!

请注意,来自 ProGuard 的错误消息确实不符合标准,因为它们很容易与在 JAR 文件根本不存在时到达的类似Ant消息混淆。 只有在最底层才会有一点 ProGuard 有问题的迹象。 因此,开始搜索传统的类路径错误等是很合乎逻辑的,但这将是徒劳的。

显然,NoClassDefFound 异常将是运行时的结果,例如,生成的可执行 JAR 文件基于缺乏 ProGuard 一致性构建。 有人称其为 ProGuard“地狱”。

为 Eclipse使用FileSync 插件,因此我可以在 Tomcat 上进行实时调试。 我收到NoClassFoundError ,因为我在 Eclipse 工作区中为bin目录添加了一个同步条目=> classes Tomcat metadata => classes ,但我还没有为 Eclipse 中的extlib目录添加文件夹同步=>

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

如果您最近在 Android Studio 中添加了 multidex 支持,如下所示:

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

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

public class MyApp extends MultiDexApplication {

不要在模块外使用测试类

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

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

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

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

例子:

错误信息:

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

POM内容:

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

Git 分支更改后出现此错误。 对于 Eclipse 的特定情况, org.eclipse.wst.common.component 文件.settings目录中缺少行。 正如你在下面看到的。

使用 Maven 安装恢复项目依赖项会有所帮助。

在此处输入图片说明

如果您使用gradlew ,请转到./gradle/wrapper/gradle-wrapper.properties并将distributionUrl更改为Gradle的正确版本。

如果您使用的是 JDK14,请尝试:

distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip

对于MeteorCordova用户,

它可能是由您使用的 Java 版本引起的。 对于 Meteor 和 Cordova,暂时坚持使用版本 8。

  1. 检查可用的 Java 版本/usr/libexec/java_home -V并查找 Java 版本 8 的路径名

  2. 设置Java version 8 export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home

  3. 检查是否完成echo $JAVA_HOME

继续并继续编码。

此错误意味着您没有添加某些依赖项。

Java 11 + Eclipse 解决方案:

如果您没有在 Eclipse 项目中使用module-info.java并且您手动添加了 JAR 文件而不是使用Maven / Gradle ,则此解决方案适合您。

  1. 右键单击项目 →构建路径配置构建路径选项卡
  2. 从模块路径中删除有问题的 JAR 文件
  3. 将 JAR 文件添加到类路径

更多信息在 Eclipse 中,modulepath 和 classpath 有什么区别? .

我删除了文件夹“buid”和“out”,IDE 用更新的内容文件再次重建了这个文件夹。

如果您使用的是 Maven,这可能是由于 pom.xml 中的依赖项的 scope 造成的,如果它们设置为“已提供”,请尝试将其更改为“编译”。

如果使用 Eclipse,请检查运行配置/依赖项。 我在使用包含在 Java 构建路径/库中的外部 jar 文件时遇到此问题,但不知何故未在运行配置/依赖项中列出。

我的Genymotion设备经常发生这种情况。

确保安装 Genymotion 的驱动器上有足够的可用内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM