一个try-catch问出这么多花样【面试题】

Java
216
0
0
2024-02-27

源码

下面代码的返回结果是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_11: istore_0 ,如下图所示

在这里插入图片描述

然后执行try-catch-finally中的方法,用到x,所以执行字节码 2: iload_0,命令,把局部变量表中的0号位置数据加载到操作数栈栈顶。如下图所示。

在这里插入图片描述

接下来执行 3: istore_1 方法,把操作数栈顶元素保存到局部变量表1号位置,如下图所示

在这里插入图片描述

接下来执行4: iconst_25: istore_0 字节码,即x = 2的代码,把2压入到操作数栈栈顶中,把栈顶元素保存到局部变量表0号位置中,如下图所示。

在这里插入图片描述

最后执行 6: iload_17: 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号位置的数据压入到操作数栈栈顶

参考

https://mp.weixin.qq.com/s/4tBjAt-lTh6-zmhW-44S6A https://www.imooc.com/wenda/detail/440500