Ответ 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
вообще, а не просто завершает всю цепочку вызовов с ошибкой.