通过阅读JVM规范,得知编译器是通过冗余来实现finally语句块的。我们可以写段代码做一个验证。
JDK版本:8
如下面的代码:
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
foo();
} catch (IOException e) {
int a = 100;
} catch (Exception e) {
int b = 200;
} finally {
int c = 300;
}
}
public static void foo() throws IOException {
}
}
根据finally的语义,我们可以确定int c = 300
这行代码一定会被执行。我们可以用javap -v Main
来看看这段代码对应的字节码:
Code:
stack=1, locals=5, args_size=1
0: invokestatic #2 // Method foo:()V
3: sipush 300
6: istore_1
7: goto 41
10: astore_1
11: bipush 100
13: istore_2
14: sipush 300
17: istore_1
18: goto 41
21: astore_1
22: sipush 200
25: istore_2
26: sipush 300
29: istore_1
30: goto 41
33: astore_3
34: sipush 300
37: istore 4
39: aload_3
40: athrow
41: return
其中,偏移量为14、17, 26、29, 和34、37的字节码就是int c = 300
对应的字节码。sipush 300
意为将300压入操作数栈,astore_N
意为将操作数栈顶元素保存到本地变量表中的第N个slot中。
由此我们可以清楚地看出,编译器确实是在每个catch
语句块后都添加了finally
块中的字节码, try
块的最后也有int c = 300
字节码的冗余。如果翻译成Java代码应该这样的:
public static void main(String[] args) {
try {
foo();
int c = 300; // 冗余
} catch (IOException e) {
int a = 100;
int c = 300; // 冗余
} catch (Exception e) {
int b = 200;
int c = 300; // 冗余
} finally {
int c = 300;
}
}
由此可知,我们在写代码时,如果finally块中的代码过多会导致字节码条数”膨胀”,因为finally中的字节码会被”复制”到try块和所有的catch块中。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/neosmith/article/details/48093427