Игра с 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
Класс NoClassDefFoundError
Брошено, если виртуальная машина Java или экземпляр ClassLoader пытается загрузить в определении класса (как часть обычного вызова метода или как часть создания нового экземпляра с использованием нового выражения) и нет определения класс можно найти.
Искаженное определение класса существовало при компиляции текущего исполняемого класса , но определение больше не может быть найдено.
Это странное сообщение об ошибке, это ошибка?
ОБНОВЛЕНИЕ: Идентификатор отчета об ошибке: 9052375
Выполняется из командной строки и печатает ожидаемую ошибку:
Проблема заключалась в том, что исключения использовались в catch
.
![введите описание изображения здесь]()
Ответ 1
Это не ошибка, и она также не имеет ничего общего со статическими методами в интерфейсах.
Сообщение 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
вообще, а не просто завершает всю цепочку вызовов с ошибкой.