提问人:Jonathan Lam 提问时间:7/31/2013 最后编辑:Peter MortensenJonathan Lam 更新时间:4/27/2023 访问量:1671689
如何解决“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);
}
}
我在这里做错了什么?
更新
在我把类放入包中(我添加到其中)后,将类路径设置为“_test”(包含图形的文件夹),编译它,然后使用(从命令行)运行它,它起作用了。Main
graphics
package graphics;
java graphics.Main
真的晚了 更新 #2
我没有使用 Eclipse(只是 Notepad++ 和 JDK),上面的更新解决了我的问题。然而,这些答案似乎很多都是针对 Eclipse 和 IntelliJ IDEA 的,但它们的概念相似。
答:
造成这种情况的一个可能原因可能是该类存在于 的类路径中,但它不存在于 的类路径中。NoClassDefFoundError
Compile time
Runtime
如果您使用的是 Eclipse,请确保文件中有 和 as 条目。shapes
linepoints
spaceobjects
.classpath
评论
java.lang.NoClassDefFoundError
指示在编译时找到某些内容,但在运行时未找到。也许你只需要将它添加到类路径中。
评论
编译代码后,最终会得到程序中每个类的文件。这些二进制文件是 Java 解释以执行程序的字节码。表示负责动态加载类的类加载器(在本例中)找不到您尝试使用的类的文件。.class
NoClassDefFoundError
java.net.URLClassLoader
.class
如果所需的类不存在,则代码将无法编译(除非加载了反射的类),因此通常此异常意味着类路径不包含必需的类。请记住,类加载器(具体来说)将在类路径中的每个条目中查找文件夹 a/b/c/ 中的包 a.b.c 中的类。 还可以指示您缺少已针对其编译并尝试使用的 .jar 文件的可传递依赖项。java.net.URLClassLoader
NoClassDefFoundError
例如,如果你有一个类,编译后你就会有一个类文件。例如,假设您的工作目录是 。该类文件必须放在 中,并且将类路径设置为 。com.example.Foo
Foo.class
.../project/
.../project/com/example
.../project/
旁注:我建议利用 Java 和 JVM 语言的惊人工具。像 Eclipse 和 IntelliJ IDEA 这样的现代 IDE 以及像 Maven 或 Gradle 这样的构建管理工具将帮助您不必担心类路径(同样多)并专注于代码!也就是说,此链接解释了如何在命令行上执行时设置类路径。
评论
我想纠正其他人的观点。NoClassDefFoundError
NoClassDefFoundError
可能由于多种原因而发生,例如:
- ClassNotFoundException -- .找不到该引用类的类,无论它在编译时是否可用(即基类/子类)。
- 类文件已找到,但在初始化静态变量时引发异常
- 找到类文件,初始化静态块时引发异常
在原始问题中,这是第一种情况,可以通过将 CLASSPATH 设置为引用的类 JAR 文件或其包文件夹来纠正。
说“在编译时可用”是什么意思?
- 引用的类在代码中使用。
例如:两个类,A 和 B(扩展 A)。如果 B 在代码中直接引用,则它在编译时可用,即A a = new B();
说“在编译时不可用”是什么意思?
- 编译时类和运行时类是不同的,例如,基类是使用子类的类名加载的,例如
Class.forName(“类名”)
例如:两个类,A 和 B(扩展 A)。代码有
A a = Class.forName("B").newInstance();
评论
package app;
NoClassDefFoundError
如果你的项目在一个包中,比如 并且你的类被调用了 ,那么编译后的文件可以输出在目录结构中,比如 。对于 IntelliJ IDEA 来说尤其如此。com.blahcode
Main
./out/com/blahcode/Main.class
尝试从 shell 或 cmd 运行时,您需要访问包含子目录的内容。cd
com
cd out
java -classpath . com.blahcode.Main
如果在编译和运行时遇到以下错误之一:
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 编译器生成的,但在运行时不知何故找不到依赖类。
让我们看一个简单的例子:
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 类 javac 类
这两个文件都已成功编译,并在与 ClassA.class 和 ClassB.class 相同的文件夹中生成了类文件
现在,由于我们要将 ClassPath 覆盖到当前工作控制器,因此我们执行以下命令 java -cp 。ClassA,它工作成功,您将在屏幕上看到输出
现在,假设您从当前目录中删除了 ClassB.class 文件。 现在你再次执行命令。java -cp 的 。ClassA 现在,它将使用 NoClassDefFoundException 来迎接您。因为在类路径(即当前工作目录)中找不到 ClassB 是 ClassA 的依赖项。
我在这个链条中的两分钱:
确保类路径包含完整路径(而不是 ),否则您仍然会遇到错误。/home/user/lib/some_lib.jar
~/lib/some_lib.jar
NoClassDefFoundError
评论
~
bash
echo ~:~
~
当运行时类加载器加载的类无法访问 Java 根加载器已加载的类时,我得到 NoClassFoundError。因为不同的类装入器位于不同的安全域中(根据 Java),所以 JVM 不允许在运行时装入器地址空间中解析已经由 rootloader 加载的类。
使用“java -javaagent:tracer.jar [您的”java“参数]”运行程序
它生成显示已加载类的输出,以及加载该类的加载程序环境。跟踪无法解析类的原因非常有帮助。
// 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即可。
在 NetBeans 项目上工作了几个月后,在收到“内存不足”警报后不久,我突然收到了 NoClassDefFoundError 消息。执行 Clean 重新生成没有帮助,但完全关闭 NetBeans 并重新打开项目后,没有错误报告。
我在使用 Android Studio 进行 Android 开发时遇到了同样的问题。提供的解决方案是通用的,对我没有帮助(至少对我而言)。
经过数小时的研究,我找到了以下解决方案,它可能对使用 Android Studio 进行开发的 Android 开发人员有所帮助。
修改设置如下:
“构建”、“执行”、“部署”→“即时运行”→首选项→ *取消选中第一个选项。
有了这个变化,我就可以启动并运行了。
Java 中的 NoClassDefFoundError:
定义:
如果某个类在编译时存在,但在运行时在 java 类路径中不可用,则会出现 NoClassDefFoundError。通常,当您获得 NoClassDefFoundError 时,您将在日志中看到以下行: 线程“main”中的异常 java.lang.NoClassDefFoundError
可能原因:
该类在 Java 类路径中不可用。
您可能正在使用 jar 命令运行程序,并且未在清单文件的 ClassPath 属性中定义类。
任何启动脚本都会覆盖 Classpath 环境变量。
因为 NoClassDefFoundError 是 java.lang.LinkageError 的子类,所以如果其中一个依赖项(如本机库)可能不可用,它也可能出现。
检查日志文件中的 java.lang.ExceptionInInitializerError。由于静态初始化失败导致的 NoClassDefFoundError 很常见。
如果您在 J2EE 环境中工作,那么 Class 在多个 Classloader 中的可见性也可能导致 java.lang.NoClassDefFoundError,请参阅示例和场景部分进行详细讨论。
可能的解决方案:
验证应用程序的类路径中是否包含所有必需的 Java 类。最常见的错误是在开始执行依赖于某些外部库的 Java 应用程序之前,没有包含所有必要的类。
应用程序的类路径是正确的,但在应用程序执行之前,Classpath 环境变量被覆盖。
验证上述 ExceptionInInitializerError 是否未出现在应用程序的堆栈跟踪中。
资源:
解决 Java J2EE 中 java.lang.NoClassDefFoundError 的 3 种方法
java.lang.NoClassDefFoundError – 如何解决未找到类 Def 错误
此答案特定于服务中发生的 java.lang.NoClassDefFoundError:
我的团队最近在升级提供服务的 rpm 后看到了此错误。rpm 和它里面的软件是用 Maven 构建的,所以看起来我们有一个编译时依赖性,只是没有包含在 rpm 中。
但是,在调查时,未找到的类与堆栈跟踪中的多个类位于同一模块中。此外,这不是最近才添加到构建中的模块。这些事实表明,这可能不是 Maven 依赖问题。
最终的解决方案:重新启动服务!
rpm 升级似乎使底层 JAR 文件上的服务文件句柄失效。然后,该服务看到一个尚未加载到内存中的类,在其 jar 文件句柄列表中搜索它,但找不到它,因为它可以从中加载该类的文件句柄已失效。重新启动服务会强制它重新加载其所有文件句柄,然后允许它在 rpm 升级后立即加载内存中未找到的类。
评论
检查您的类中是否有静态处理程序。如果是这样,请小心,因为静态处理程序只能在具有循环器的线程中启动,因此可以通过以下方式触发崩溃:
首先,在一个简单的线程中创建类的实例并捕获崩溃。
然后在主线程中调用 Class 的字段方法,你会得到 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);
}
如果您使用多个模块,您应该有
dexOptions {
preDexLibraries = false
}
在构建文件中。
此异常的一个错误来源可能源于 Proguard 的定义不一致,例如缺少
-libraryJars “path.to.a.missing.jar.library”。
这就解释了为什么编译和运行工作正常,因为 JAR 文件在那里,而清理和构建失败。请记住在 ProGuard 设置中定义新添加的 JAR 库!
请注意,来自 ProGuard 的错误消息确实不符合标准,因为它们很容易与 JAR 文件根本不存在时到达的类似 Ant 消息混淆。只有在最底部才会有一丝 ProGuard 陷入困境的迹象。因此,开始搜索传统的类路径错误等是很合乎逻辑的,但这将是徒劳的。
显然,NoClassDefFound 异常将是运行时的结果,例如,生成的可执行 JAR 文件是基于缺乏 ProGuard 一致性构建的。有人称它为ProGuard“地狱”。
我今天遇到了这个问题。我有一个 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);
}
我使用 Eclipse 的 FileSync 插件,因此我可以在 Tomcat 上进行实时调试。我收到了 ,因为我在 for Tomcat 的 Eclipse 工作区中为该目录添加了一个同步条目,但我没有为 Eclipse 中的目录添加文件夹同步NoClassFoundError
bin
=> classes
metadata
extlib
=>
C:\Users\Stuart\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\webapps\myApp\WEB-INF\lib
我正在开发一个基于 Eclipse 的应用程序,也称为 RCP(富客户端平台)。 而且我在重构(将一个类从插件移动到一个新类)后一直面临这个问题。
清理项目和 Maven 更新无济于事。
该问题是由尚未自动更新的 Bundle-Activator 引起的。在 MANIFEST 下手动更新 Bundle-Activator。新插件中的 MF 解决了我的问题。
如果您最近在 Android Studio 中添加了 multidex 支持,如下所示:
// To support MultiDex
implementation 'com.android.support:multidex:1.0.1'
因此,您的解决方案只是从 MultiDexApplication 而不是 Application 扩展:
public class MyApp extends MultiDexApplication {
对于我的项目,解决问题的是 Chrome 浏览器和 chromedriver 不兼容。我有一个非常旧版本的驱动程序,甚至无法打开浏览器。我刚刚下载了两者的最新版本并解决了问题。
我是如何发现问题的?因为我使用 Selenium 原生 Firefox 驱动程序运行我的项目,我的应用程序中包含旧版本的 FF。我意识到问题是浏览器和驱动程序之间的不兼容。
希望这可以帮助任何与我有类似问题的人,这产生了同样的错误消息。
不要在模块外部使用测试类
我没有解决方案,只是“编译时存在,运行时不存在”情况的另一种风格。
我试图使用一种非常方便的方法,该方法来自另一个位于不同模块中的测试类的 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 install 恢复项目依赖项会有所帮助。
如果您使用的是 ,请转到并更改为正确的 Gradle 版本。gradlew
./gradle/wrapper/gradle-wrapper.properties
distributionUrl
如果您使用的是 JDK14,请尝试:
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
这可能是由您使用的 Java 版本引起的。对于 Meteor 和 Cordova,暂时坚持使用版本 8。
检查可用的 Java 版本并查找 Java 版本 8 的路径名
/usr/libexec/java_home -V
设置 Java 版本 8 的路径
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
检查是否完成
echo $JAVA_HOME
继续编码。
Java 11 + Eclipse 解决方案:
如果您未在 Eclipse 项目中使用,并且您手动添加了 JAR 文件而不是使用 Maven/Gradle,则此解决方案适合您。module-info.java
- 右键单击项目→“生成路径”→“配置生成路径”→“库”选项卡
- 从模块路径中删除有问题的 JAR 文件
- 将 JAR 文件添加到类路径中
更多信息可以在 In Eclipse, modulepath 和 classpath 之间有什么区别?。
如果要从 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>
<!-- Workaround for Maven bug #MJAR-156 (https://jira.codehaus.org/browse/MJAR-156) -->
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
</configuration>
</plugin>
请注意,上面的示例在类路径中用作分隔符(它对 Windows 平台有效)。在 Linux 上,替换为 。;
;
:
例如
java -classpath ./libs/phone.jar:./libs/anotherlib.jar:./dialer.jar
com.company.dialer.DialerServer
我删除了文件夹“buid”和“out”,IDE使用更新的内容文件再次重建了这个文件夹。
评论
package graphics;
graphics
package graphics.shapes