欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java代码中的finally块,在字节码层面的变化

程序员文章站 2022-05-12 14:19:47
...

java代码中的finally块,会在字节码层面上多加一层对于any异常的处理

结论

不论在方法上显式抛出异常了,还是在代码块中try-catch了,如果代码块中存在finally块,当前方法的Code属性中就会出现异常表信息,且Code属性中bytecode部分会多出一套对any异常的处理

这篇文章部分细节不会说明

对比加和不加finally块

首先是不加finally块的

public class Study3 {

	public void test() {
		try {
			InputStream in = new FileInputStream("AAA"); 
			ServerSocket socket = new ServerSocket(9999);
			socket.accept();
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
}

我们使用javap -verbose 来反编译我们写的类
其他部分我们不关注,只关注 test方法这一块
java代码中的finally块,在字节码层面的变化
我们在上图中 关注红框部分,首先是max_locals= 3最大局部变量slot占据数量是3,我们知道非静态方法中,jvm会将对当前类对象引用隐式传入方法中,我们看局部变量表部分,我们catch的异常e和try中变量in共用了同一个1号slot,原因是因为try 和catch的域不同,出现异常被catch捕获了,try里面变量生命周期结束,所以catch中e可以占用之前try里面变量的slot
如果可以请读一下Code中byteCode部分,加finally之后会发生变化
注意此时异常表 Exception table里面存在是我们定义的对 Exception异常的捕获

然后我们加上finally块(注意finally块里面必须有代码,若没有代码则跟等同于没有finally块)

public void test() {
		try {
			InputStream in = new FileInputStream("AAA"); 
			ServerSocket socket = new ServerSocket(9999);
			socket.accept();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("aaa");
		}
	}

java代码中的finally块,在字节码层面的变化
java代码中的finally块,在字节码层面的变化
加finally块之后最显著变化,我们max_locals变成了4,在Code属性中byteCode体现在多了一部分对any异常处理的代码,看图中红框部分 , astore_3 将对除Exception以外的any异常抓出并存储到本地slot是3的变量里面 ,在这里就跟我们正常catch中异常处理不同了,因为catch里面异常变量会存储在我们已有的slot内,而加finally额外多出对any异常处理的异常变量则会额外占用一个slot位置,这个局部变量不会体现在局部变量表 LocalVariableTable里面,所以我们在局部变量表里面看到最大的索引是2

在显式抛出异常的方法中加finally块我就不演示了,显式抛出异常的方法中如果没有finally块,反编译结果中只会有Exceptions属性,不会有Exception table异常表信息,如果加了finally块,就会多出异常表信息,里面是对any异常做的处理,大家可以自己试一下

不喜勿喷,有问题请留言

相关标签: java字节码 java