鉴于此计划:
class Test {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException npe) {
System.out.println("In catch");
} finally {
System.out.println("In finally");
}
}
}
Sun的javac
(v 1.6.0_24)生成以下字节码:
public static void main(java.lang.String[]);
// Instantiate / throw NPE
0: new #2; // class NullPointerException
3: dup
4: invokespecial #3; // Method NullPointerException."<init>":()V
7: athrow
// Start of catch clause
8: astore_1
9: getstatic #4; // Field System.out
12: ldc #5; // "In catch"
14: invokevirtual #6; // Method PrintStream.println
17: getstatic #4; // Field System.out
// Inlined finally block
20: ldc #7; // String In finally
22: invokevirtual #6; // Method PrintStream.println
25: goto 39
// Finally block
// store "incomming" exception(?)
28: astore_2
29: getstatic #4; // Field System.out
32: ldc #7; // "In finally"
34: invokevirtual #6; // Method PrintStream.println
// rethrow "incomming" exception
37: aload_2
38: athrow
39: return
使用以下异常表:
Exception table:
from to target type
0 8 8 Class NullPointerException
0 17 28 any
28 29 28 any
我的问题是:为什么它包含异常表中的最后一个条目?!
据我了解,它基本上是“如果astore_2
抛出异常,抓住它,并重试相同的指令”。
即使使用空的try / catch / finally子句(例如
)也会生成此类条目try {} catch (NullPointerException npe) {} finally {}
一些观察
astore
instruction的任何运行时异常。VirtualMachineError
是合法的。我猜这个特殊的条目可以防止任何此类错误从该指令传播出来。答案 0 :(得分:8)
只有两种可能的解释:编译器包含一个错误,或者由于不明原因而放置了一种水印。
该条目肯定是假的,因为finally块本身抛出的任何异常必须将执行流发送到外部异常处理程序或最后阻塞,但绝不会“再次”运行相同的finally块。
此外,一个很好的证据表明它是一个错误/水印,是Eclipse(可能还有其他Java编译器)没有生成这样的条目,即便如此,Eclipse生成的类在Sun的JVM上运行良好。
也就是说,这篇文章很有意思,因为它似乎是有效的并且验证了类文件。如果我是JVM实现者,我会忽略该条目并填写Sun / Oracle的错误!
答案 1 :(得分:6)
看看OpenJDK 7源代码,我冒昧地猜测原因
最后28 29 28 any
异常表条目是因为代码
处理astore
字节码(见code从第1871行开始)即可
如果弹出值,则抛出java.lang.LinkageError
异常
来自操作数堆栈的不是returnAddress
或reference
类型(参见
astore)的Java虚拟机规范,他们想要这个
错误条件显示在堆栈跟踪上。
如果操作数堆栈上存在错误的操作数类型,JVM将会
清除操作数堆栈(摆脱那个坏操作数),放一个LinkageError
在操作数堆栈上,这次再次执行astore
字节码
使用提供的astore
JVM成功执行LinkageError
字节码
对象参考。有关详细信息,请参阅athrow文档。
我非常怀疑在{期间}投掷LinkageError
的根本原因
astore
处理归因于complexities JSR/RET subroutines引入字节码验证(OpenJDK更改
6878713,6932496和7020373是。{
最近证据JSR
的复杂性持续存在;我确信Sun / Oracle还有其他
我们在OpenJDK中没有看到的闭源测试。 OpenJDK 7020373更改使用LinkageError
来验证/使测试结果无效。
答案 2 :(得分:1)
我的理解是第二个异常表条目是编译器添加的隐式catch everything子句,用于覆盖正文或catch处理程序中抛出的任何异常/错误,第三个条目是该隐式catch上的守护强制流经最后的执行。