如果 NoClassDefFoundError 是由 ClassNotFoundException 引起的,为什么 Java 希望你同时捕获这两个可抛出项?

2022-09-03 01:51:26

当我运行此代码时,应用程序退出一个 ClassNotFoundException:

//uncaught ClassNotFoundException
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (NoClassDefFoundError e)
{
}

当我尝试编译此代码时,编译器抱怨 ClassNotFoundException 不可访问,因为它不是从 try-catch 语句的 try 子句中引发的。

//Won't compile
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (ClassNotFoundException e)
{
}

当我运行此代码时,唯一捕获的可抛出项是 NoClassDefFoundError。

//catches throwable of type java.lang.NoClassDefFoundError,
//with a java.lang.ClassNotFoundException as its cause
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (Throwable e)
{
    System.out.println(e.getClass().getName());
    System.out.println(e.getCause().getClass().getName());
}

以下代码将编译并捕获错误(并且仅捕获错误),但它很笨拙:

//possible workaround
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
    if (1 == 0) throw new ClassNotFoundException(); // we want the code to compile
}
catch (ClassNotFoundException e)
{
    System.out.println("ex");
}
catch (NoClassDefFoundError e)
{
    System.out.println("err");
}

然而,当我写以下内容时,我可以逃脱而没有一个捕获子句的错误原因:

//and yet this works just fine...
try
{
    throw new Error(new IOException());
}
catch (Error e)
{
    System.out.println("err");
}

示例 3 使我得出这样的结论:可投掷对象是 NoClassDefFoundError。示例 1 使我得出结论,可抛出的是 ClassNotFoundException。然而,示例 2 表明 java 甚至不允许我编写代码来正确捕获 ClassNotFoundException。

就在我即将得出结论,这里的问题是异常引起的错误时,我运行了上一个示例中所示的代码,该代码表明这不是规则。

有人可以解释一下这里发生了什么吗?

PS:这是堆栈跟踪:

 java.lang.NoClassDefFoundError: com/my/pckage/MyClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at Main$MyClassLoader.getClasses(Main.java:78)
at Main.main(Main.java:109)
 Caused by: java.lang.ClassNotFoundException: com.my.pckage.MyClass
at java.lang.ClassLoader.findClass(ClassLoader.java:522)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 4 more

答案 1

因此,您误解了堆栈跟踪。

java.lang.NoClassDefFoundError: com/my/package/MyClass
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at Main$MyClassLoader.getClasses(Main.java:78)
    at Main.main(Main.java:109)
Caused by: java.lang.ClassNotFoundException: com.my.package.MyClass

您的代码正在生成 .根本原因是 .请记住,这是 Throwable 类的一个属性,在打印堆栈跟踪时,Java 将显示有关直接异常及其根本原因的信息。很难说为什么该方法在内部失败,但有一件事是肯定的 - 你不能在包名称中使用关键字。NoClassDefFoundErrorClassNotFoundExceptioncausedefinepackage


答案 2

当找到类的.class时,会发生 NoClassDefFoundError,但无法从该.class构造该类。

有几种常见的不同情况,以及一些更晦涩难懂的情况。

  • .class文件包含与类文件名/包不匹配的名称(和包)
  • 找不到验证和初始化类所需的类
  • 类初始化期间出错

在大多数这些场景中,还有另一个错误或异常,该错误或异常发生在较早之前,由类装入器捕获,并且新错误被发出信号。

目前尚不清楚上述异常回溯中究竟发生了哪种情况,但我猜是某种名称不匹配。


推荐