.

.

.

.

.

今天有同事和我探讨在群里看到的一道有趣的题目,在探讨的过程中让我搞清楚了一些曾经模糊的概念,特此记录下来。

题目给出如下代码,问运行后打印的结果是什么。

 public static void main(String []args) {
System.out.println(fun());
}
public static int fun () {
int x = 0;
try {
x = 1;
} finally {
++x;
}
try {
return x;
} finally {
++x;
}
}

尝试运行,结果如下:(输出 2)

 >$ javac -g No1.java
>$ javac No1 >$

为何输出是 2 而不是 3 呢,这个可能让很多小伙伴有所疑惑,我们通过 javap 指令查看字节码来解释这个疑问。

首先来看一些前置知识——java 字节码指令的 iconst_n、iload_n、istore_n 和 iinc。

指令 意义
iconst_n 表示将整型常量 n 推入栈顶,n 的范围是 -1 ≤ n ≤ 5。
iload_n

表示将局部变量表中第 n 个槽的整型变量加载到操作数栈顶。

istore_n

表示将操作数栈顶的整型值弹出,并存储到局部变量表的第 n 个槽中。

iinc a b 表示将局部变量表第 a 个槽中的值增加 b,并将结果存回 a 槽。

好,有了上面四个指令的基础就够了,接下来我们看一下上面代码的字节码。

>$ javap -c -l No1
public static int fun();
Code:
: iconst_0 // 常量 0 入栈顶
: istore_0 // 将栈顶的 0 弹出并存入局部变量表的第 0 个槽中
: iconst_1 // 常量 1 入栈顶
: istore_0 // 弹出栈顶的 1 并存入局部变量表的第 0 个槽中,覆盖原值
: iinc , // 将局部变量表第 0 个槽中的值加 1,并将结果存回局部变量表第 0 个槽中,覆盖原值
: goto // 跳转到 16
: astore_1
: iinc ,
: aload_1
: athrow // 下面两行是重点,将局部变量表第 0 个槽中的值拷贝了一个副本到局部变量表第 1 个槽中
: iload_0 // 将局部变量表第 0 个槽中的值加载到栈顶
: istore_1 // 弹出栈顶的值并存储到局部变量表第 1 个槽中
: iinc , // 将局部变量表第 0 个槽中的值加 1,并将结果存回局部变量表第 0 个槽中,覆盖原值
: iload_1 // 重点:将局部变量表中第 1 个槽中的值加载到栈顶(并没有加载第 0 个槽中的值)
: ireturn // 返回栈顶的值
: astore_2
: iinc ,
: aload_2
: athrow
Exception table:
from to target type
any
any

上面的文字太抽象,可以对照着 图1 的内容来理解。

图1 执行过程内存图例

在 图1 中,红色的字表示字节码的行号,黑色的字表示执行此行字节码之后,对应的内存中的值的变化。

不难看出,在字节码第 16、17 行,将 x 的值从局部变量表的第 0 个槽中拷贝了一个副本,保存在局部变量表的第 1 个槽中,而最后执行 ireturn 指令之前,将此副本加载到了栈顶,因此返回的值是在 finally 运算之前就确定下来了的,此后 finally 中再次对 x 的运算都只是在局部变量表的第 0 个槽中做的,所以并不会影响到 ireturn 指令返回的值。

总结:

经过 LZ 几番测试发现,无论在 try 中 return 的变量是否参与了后面在 finally 中的计算,都会被拷贝一个副本出来。

而 return 没有在 try 块中时,被 return 的变量则不会被拷贝副本。

由此可见,当 try 遇到 return 时,变量被“特殊照顾”了一下。

*注意,以上测试仅使用了 int 类型(基本数据类型),没有测试 return 引用类型的情况。

当 return 遇到 try的更多相关文章

  1. jsp中出现onclick函数提示Cannot return from outside a function or method

    在使用Myeclipse10部署完项目后,原先不出错的项目,会有红色的叉叉,JSP页面会提示onclick函数错误 Cannot return from outside a function or m ...

  2. JavaScript中fn()和return fn()

    看博客时,注意到return的重要性 参考:http://www.cnblogs.com/raoyunxiao/p/5644032.html 看似反常的例子: var i = 0; function ...

  3. 【知识积累】try-catch-finally+return总结

    一.前言 对于找Java相关工作的读者而言,在笔试中肯定免不了遇到try-catch-finally + return的题型,需要面试这清楚返回值,这也是这篇博文产生的由来.本文将从字节码层面来解释为 ...

  4. Ajax接收不到PHP return后的结果的原因

    PHP在处理ajax返回值的时候,如果使用return如 return $result会失败,echo $result却没问题. 解释原因如下: 1.ajax请求从服务器端读取返回值,而且这些返回值必 ...

  5. oncopy="document.selection.empty()"跟oncopy="return false"什么区别?

    实现效果一样,禁止复制. 区别: oncopy="document.selection.empty()"  没禁止,只是把它复制的内容,变成空了: oncopy="ret ...

  6. 自动判断应该Ajax还是return

    起因 最近回顾以前的代码,发现一个偶尔会见到的现象.一个类里面的方法可能需要Ajax返回,也有可能需要函数return.这个现象发生在网站MVC中的 逻辑层(或模型层),示例如下.IndexCtrl是 ...

  7. jquery中ajax用return来返回值无效

    jquery中,ajax返回值,有三种写法,只有其中一种是成功的 /** * async:false,同步调用 * 返回1:2 * 失败 * 分析:ajax内部是一个或多个定义的函数,ajax中ret ...

  8. 高程(3):操作符、for、for...in循环、break/continue/return语句、函数等

    1.关系操作符 注意点:1)比较操作数是两个字符串,是比较字符串的字符编码值. 如:"a" > "b"  返回 false:"a" & ...

  9. [转载]js中return的用法

    一.返回控制与函数结果,语法为:return 表达式; 语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果 二.返回控制,无函数结果,语法为:return;  在大多数情况下,为事件处理函 ...

  10. 解决springmvc报No converter found for return value of type: class java.util.ArrayList问题

    一.背景 最近闲来无事,想自己搭建一套Spring+SpringMVC+Mybatis+Mysql的环境(搭建步骤会在以后博客中给出),结果运行程序时,适用@ResponseBody注解进行返回Lis ...

随机推荐

  1. QtQuick大坑笔记之Http的Get与Post操作(带cookie)

    前言 最近在为单位做一个简单的手机App,基于Qt技术栈的选择了QtQuick来开发.不得不说QtQucik开发的确舒服,很多东西都不用写就可以只用,UI定义起来也比较自由.但是本人想通过cookie ...

  2. go知识点和注意事项

    bin目录下面存的是编译之后可执行的文件,pkg下面存放的是应用包,src下面保存的是应用源代码 Go 语言不支持函数重载特性的主要原因是函数重载需要进行多余的类型匹配影响性能: 目前 Go 没有泛型 ...

  3. VirtWire 向客服发ticket

    1 首先需要登录自己的账户 2 点击网页的Open Ticket 3 选择要发送何种类型的ticket 4 写自己的问题,包括一个合适的主题,选择你发ticket是针对哪个vps(一个账户下可以ord ...

  4. [COCI2013]DLAKAVAC

    [COCI2013]DLAKAVAC 题目大意: 有一个长度为\(m(m\le1500)\)的\(01\)串\(A\),进行\(k(k\le10^{18})\)次操作.一次操作完的串中若\(A_i=1 ...

  5. [HNOI/AHOI2018]道路

    Description: W 国的交通呈一棵树的形状.W 国一共有\(n - 1\)个城市和\(n\)个乡村,其中城市从\(1\)到\(n - 1\) 编号,乡村从\(1\)到\(n\)编号,且\(1 ...

  6. Coins [POJ1742] [DP]

      Description 给出硬币面额及每种硬币的个数,求从1到m能凑出面额的个数. Input 多组数据,每组数据前两个数字为n,m.n表示硬币种类数,m为最大面额,之后前n个数为每种硬币的面额, ...

  7. Redis设计与实现:读书笔记之二

    1.数据库 Redis服务器一般包含多个db,默认16个. 切换数据库 每个redis客户端都有自己的目标数据库,默认为0,可以通过select 1,切换数据库. 设置键的生存周期和过期时间 PTTL ...

  8. jsp下载文件的实现方法及注意事项 (转)

    jsp中实现文件下载,最简单的方式是在网页上做超级链接,如:<a href="music/abc.mp3">点击下载</a>. 但是,这样服务器上的目录资源 ...

  9. Schaepher 博客目录

    update: 2017-03-16 福州大学2015年秋软件工程实践课 软工课程作业目录 软工实践课程总结 团队博客 软件案例分析优秀链接汇总 Android Android学习笔记: (一):th ...

  10. JAVA自学笔记25

    JAVA自学笔记25 1.GUI 1)图形用户接口,以图形的方式,来显示计算机操作的界面,更方便更直观 2)CLI 命令行用户接口,就是常见的Dos,操作不直观 3) 类Dimension 类内封装单 ...