当我运行Java应用程序时,我得到了一个NoClassDefFoundError。造成这种情况的典型原因是什么?
当前回答
虽然这可能是由于编译时和运行时之间的类路径不匹配造成的,但这并不一定是真的。
在这种情况下,记住两到三个不同的异常是很重要的:
java.lang.ClassNotFoundException This exception indicates that the class was not found on the classpath. This indicates that we were trying to load the class definition, and the class did not exist on the classpath. java.lang.NoClassDefFoundError This exception indicates that the JVM looked in its internal class definition data structure for the definition of a class and did not find it. This is different than saying that it could not be loaded from the classpath. Usually this indicates that we previously attempted to load a class from the classpath, but it failed for some reason - now we're trying to use the class again (and thus need to load it, since it failed last time), but we're not even going to try to load it, because we failed loading it earlier (and reasonably suspect that we would fail again). The earlier failure could be a ClassNotFoundException or an ExceptionInInitializerError (indicating a failure in the static initialization block) or any number of other problems. The point is, a NoClassDefFoundError is not necessarily a classpath problem.
其他回答
当静态初始化器试图加载一个在运行时不可用的资源包时,也会发生NoClassDefFoundError,例如受影响的类试图从META-INF目录加载一个属性文件,但不存在。如果你没有捕获NoClassDefFoundError,有时你将无法看到完整的堆栈跟踪;为了克服这个问题,你可以临时为Throwable使用一个catch子句:
try {
// Statement(s) that cause(s) the affected class to be loaded
} catch (Throwable t) {
Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}
这是迄今为止我找到的最好的解决办法。
假设我们有一个名为org的包。Mypackage包含的类:
HelloWorld(主类) SupportClass UtilClass
定义这个包的文件物理存储在目录D:\myprogram (Windows)或/home/user/myprogram (Linux)下。
文件结构如下所示:
当调用Java时,我们指定要运行的应用程序的名称:org.mypackage.HelloWorld。但是,我们还必须告诉Java在哪里查找定义包的文件和目录。所以要启动程序,我们必须使用下面的命令:
确保在module:app和module:lib中匹配:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
下面是演示java.lang.NoClassDefFoundError的代码。具体的解释请看Jared的回答。
NoClassDefFoundErrorDemo.java
public class NoClassDefFoundErrorDemo {
public static void main(String[] args) {
try {
// The following line would throw ExceptionInInitializerError
SimpleCalculator calculator1 = new SimpleCalculator();
} catch (Throwable t) {
System.out.println(t);
}
// The following line would cause NoClassDefFoundError
SimpleCalculator calculator2 = new SimpleCalculator();
}
}
SimpleCalculator.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
有一个有趣的例子,你可能会看到很多NoClassDefFoundErrors:
在类的静态块中抛出一个RuntimeException 拦截它(或者如果它在测试用例中抛出并不重要) 尝试创建该类的实例
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
try {
new Example();
} catch (Throwable ignored) { //simulating catching RuntimeException from static block
// DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError将伴随来自静态块RuntimeException的ExceptionInInitializerError一起抛出。
当你在UNIT TESTS中看到NoClassDefFoundErrors时,这一点尤其重要。
在某种程度上,您在测试之间“共享”静态块执行,但初始的ExceptionInInitializerError将仅在一个测试用例中。第一个使用有问题的Example类。其他使用Example类的测试用例只会抛出NoClassDefFoundErrors。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap