源码
下面代码的返回结果是1不是2,下面从字节码的角度分析一下原因
public class Start { public static void main(String[] args) { int demo = demo(); System.out.println(demo); } public static int demo() { int x = 1; try { return x; } finally { x = 2; } } }
代码字节码分析
获取方法的字节码命令为
javap -v xxx.class
上面代码的字节码部分如下图所示(其中红色的字为解析,下面会对详细内容进行解释)
首先要明确该段代码中有一个操作数栈和局部变量表,如下图所示
当程序执行 int x = 1,时会有两个操作,常量1会压入操作数栈栈顶,然后弹出栈顶元素赋值为局部变量表的x的位置,对应字节码中的0: iconst_1 , 1: istore_0 ,如下图所示
然后执行try-catch-finally中的方法,用到x,所以执行字节码 2: iload_0,命令,把局部变量表中的0号位置数据加载到操作数栈栈顶。如下图所示。
接下来执行 3: istore_1 方法,把操作数栈顶元素保存到局部变量表1号位置,如下图所示
接下来执行4: iconst_2 , 5: istore_0 字节码,即x = 2的代码,把2压入到操作数栈栈顶中,把栈顶元素保存到局部变量表0号位置中,如下图所示。
最后执行 6: iload_1 , 7: ireturn 字节码,把局部变量表1号位置上数据压入到操作数栈栈顶,返回操作数栈顶元素,如下图所示
源码拓展
如果代码想返回2,可以有如下操作
public static int demo() { int x = 1; try { return x; } finally { x = 2; return x; } }
或者
public static int demo() { int x = 1; try { } finally { x = 2; } return x; }
字节码命令部分介绍
iconst_n
把n压入到操作数栈栈顶,n为表示具体的操作值,比如int x =5,则执行iconst_5命令。
不过也有其他的命令,当int取值-1~ 5采用iconst指令,取值-128~ 127采用bipush指令,取值-32768~ 32767采用sipush指令,取值-2147483648~2147483647采用 ldc 指令。
int x =1; int y =11;
对应的字节码如下图所示
istore_n
把操作数栈栈顶元素保存到局部变量表n号位置
iload_n
把局部变量表n号位置的数据压入到操作数栈栈顶