簡體   English   中英

為什么我得到NoClassDefFoundError異常而不是StackOverflow錯誤?

[英]Why am I getting a NoClassDefFoundError exception rather than a StackOverflow error?

玩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實例嘗試加載類的定義(作為普通方法調用的一部分或作為使用新表達式創建新實例的一部分)並且無法找到類的定義,則拋出該異常。

搜索的類定義在編譯當前正在執行的類時存在, 但無法再找到該定義

這是一個奇怪的錯誤消息,它是一個錯誤嗎?

更新: 錯誤報告ID:9052375

在命令行中執行並打印預期的錯誤: 問題是,在使用的異常catch

在此輸入圖像描述

這不是錯誤,它也與接口中的靜態方法無關。

java.lang.instrument ASSERTION FAILED消息也不相關,只是從IDE運行代碼的工件。 從命令行運行相同的類將僅Exception in thread "main"導致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()所需的類,則代碼將按預期運行(打印由StackOverflowError引起的InvocationTargetException的堆棧跟蹤:

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 ,而不是簡單地用錯誤終止整個調用鏈。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM