A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

今天看到有几个帖子是讲try/finally语句中try语句体包含return语句的执行顺序问题,我做了一下深入的了解,下面进行分析
首先,来看一段代码:
  1. public class TestTryFinally {
  2. public static void main(String[] args) {
  3.   test();
  4. }
  5. public static void test() {
  6.   int x = 5;
  7.   try{
  8.    System.out.println("try 语句-----x值:"+x);
  9.   }finally{
  10.    x++;
  11.    System.out.println("finally 语句-----x值:"+x);
  12.   }
  13. }
  14. }
复制代码
想必大家都很清楚这段代码的输出结果,对的,这段代码的输出结果是:
try 语句-----x值:5
finally 语句-----x值:6
先执行try语句体,再执行finally语句体,现在,代码稍微改动一下
  1. public class TestTryFinally {
  2. public static void main(String[] args) {
  3.   System.out.println(test());
  4. }
  5. public static int test() {
  6.   int x = 5;
  7.   try{
  8.    return x;
  9.   }finally{
  10.    x++;
  11.    System.out.println("finally 语句-----x值:"+x);
  12.   }
  13. }
  14. }
复制代码
大家再看输出结果是什么呢?是不是大多数人认为结果如下呢:
finally 语句-----x值:6
6

实际上,结果如下:
finally 语句-----x值:6

5

这该怎么解释呢,既然先执行了finally里的语句,那么x的值应该改变了的,可是为什么try里面返回的值还是原来的那个呢,这个问题可以通过反编译查看字节码指令来解释。(为了更加简洁字节码,这里把上面代码中的finally区域里的打印语句省掉)

然后通过如下指令得到字节码:javap -c TestTryFinally

得到的字节码如下:


直接看test方法的字节码

0:iconst_5   //将int型的5入栈

1:istore_0   //将int类型值存入局部变量0

2:iload_0    //从局部变量0中装载int类型值(装入5)

3:istore_1  //将int类型值存入局部变量1(这一句等于就是把5又放入到索引为1的变量中去)

4:iinc   0,1   //把局部变量区索引为0的变量加1(在这里就是执行finally语句体中的x++)

5:iload_1   //从局部变量1中装载int类型值(装入局部变量1中的值,这个值为5)

6:ireturn   //从方法中返回int类型数据(返回5)

7://后面的就是抛出异常时的代码,这里就不进行分析

从分析字节码可以看出,在try语句返回之前先将x存入到另一个变量中,再进行finally里面的语句(x++)

在finally里面语句执行完成后,再从之前的变量里取出值5,所以不管你在finally里怎么改变x的值,try里返回的

已经不会改变了。

现在,就已经可以对这段代码有一个比较深的理解了。

总结:如果try中有return语句时(注:finally语句体中没有return语句)当执行到return语句时,先把要return的值

存放在另一个新建的变量中,在finally里执行完后,再从刚才新建的变量中取出值进行返回。



另:如果try语句和finally语句中都含有return 语句时,try语句体中的return会被隐藏掉。


字节码.jpg (58.05 KB, 下载次数: 9)

字节码.jpg

评分

参与人数 1技术分 +1 收起 理由
唐志兵 + 1 赞一个!

查看全部评分

2 个回复

倒序浏览
第二次发帖,排版格式不是很好,大家包涵包涵哈
回复 使用道具 举报
很给力啊!!线收藏着,看完今天的视频任务好好研究一下!{:soso_e113:}
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马