玩 Java(特别是 v9)我发现了这种情况:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
interface A {
static A staticMethod() {
try {
Method method = A.class.getDeclaredMethods()[0];
return (A) method.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class Test {
public static void main(String[] args) {
A.staticMethod();
}
}
该程序流应该会导致 StackOverflow 错误,但是,我收到了 NoClassDefFoundError
。
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 880
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 880
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 880
Exception in thread "main"
Exception: java.lang.NoClassDefFoundError thrown from the UncaughtExceptionHandler in thread "main"
根据 Javadoc
Class NoClassDefFoundError
Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
这是一个奇怪的错误信息,是一个错误吗?
更新:错误报告 ID:9052375
从命令行执行并打印出预期的错误:
问题是,catch
中使用的异常。
最佳答案
这不是错误,也与接口(interface)中的静态方法无关。
java.lang.instrument ASSERTION FAILED
消息也不相关,它只是从 IDE 运行代码的产物。从命令行运行相同的类只会导致 Exception in thread "main"
。
让我们将您的示例简化为
public class Test {
public static void main( String[] args ) throws Exception {
recursive();
}
public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
发生了什么:
- 正如预期的那样,递归方法会导致
StackOverflowError
。 StackOverflowError
被包装到InvocationTargetException
中,这是从对method.invoke()
的最深层嵌套调用中抛出的。InvocationTargetException
立即被捕获,JVM 尝试执行printStackTrace()
但为了执行此操作,它需要加载一些类。但请记住,此时堆栈已耗尽,任何重要的方法都会再次触发StackOverflowError
,这正是类加载器尝试加载打印堆栈所需的某个类时发生的情况痕迹。类加载器确实找到了该类,但无法加载和初始化它,并将其报告为NoClassDefFoundError
。
下面的代码将证明InvocationTargetException
确实包装了StackOverflowError
:
public class Test {
public static void main( String[] args ) throws Exception {
recursive();
}
public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
System.out.println(e);
System.out.println(e.getTargetException());
}
}
}
下面的代码将证明,如果执行 printStackTrace()
所需的类已经加载,则代码将按预期运行(打印堆栈跟踪 InvocationTargetException
导致来自 StackOverflowError
:
public class Test {
public static void main( String[] args ) throws Exception {
new Exception().printStackTrace(); // initialize all required classes
recursive();
}
public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
悬而未决的问题是为什么反射 API 会处理 StackOverflowError
,而不是简单地用错误终止整个调用链。
关于java - 为什么我得到的是 NoClassDefFoundError 异常而不是 StackOverflow 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48392860/