`
yuexiaodong
  • 浏览: 70412 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一道经典笔试题

阅读更多

下面是一道经典的面试题:try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 

很多人回答return在后,但是所给的理由不够充分;或者有些说return在前如http://bbs.csdn.net/topics/60474475;还有的说在return中间执行等等;

首先说一下,我的答案如下:finally在return返回之前执行。在执行finally之前,程序碰到return,首先计算机return后面的表达式,并将结果存储到一个临时变量,然后开始执行finally中的语句,但此时的语句已经无法影响到需要返回的临时变量,执行完finally之后,取出临时变量的值返回;下面用程序证明我的观点:

 

      int testtry() {
		int x = 5;
		try {
			return x=2; 
		} finally {
			x=x+2;
		}
	}

 该函数的返回值应该为1;使用bytecodeview可以查看编译后的字节码文件:

 

各个字节指令的含义详见(http://cooldatabase.iteye.com/blog/637797

 

 
0 iconst_5 
 1 istore_1 //将5存入局部变量1
 2 iconst_2 //将常量2存入栈
 3 dup  //复制栈顶
 4 istore_1 //将2存入局部变量1
 5 istore_3 //将2存入局部变量3
 6 iinc 1 by 2 //对局部变量1自增2,可见对局部变量3没有影响
 9 iload_3  //加载局部变量3
10 ireturn //返回局部变量3,即为2
11 astore_2
12 iinc 1 by 2
15 aload_2
16 athrow

由于JVM虚拟机对程序首先检查优化使用的标准优化技术有:代码提升,公共的子表达式清除、循环展开(unrolling)、范围检测清除、死代码清除、数据流分析,还有各种在静态编译语言中不实用的优化技术,例如虚方法调用的聚合内联,所以首先计算return后面的表达式,为了证明这点,我对代码稍作修改如下:

	int testtry() {
		int x = 5;
		try {
			return x=(x+3);  //证明先计算表达式
		} finally {
			x=x+2;
		}
	}

 得到的字节码如下:

 0 iconst_5
 1 istore_1
 2 iinc 1 by 3  //可见首先计算表达式
 5 iload_1  //结果存于局部变量1即x中
 6 istore_3
 7 iinc 1 by 2
10 iload_3
11 ireturn
12 astore_2
13 iinc 1 by 2
16 aload_2
17 athrow

 由上可以证明我的观点,对于有return 返回值的try finally结构来说,fianlly先执行,但是在finally里面的操作局部变量不再对返回值造成影响,返回的结果是原来计算保存在临时变量的结果,其实这里只是延迟return返回而已。

 

对于try finally结构带有return语句的问题,可以参考Java虚拟机规范中相关章节,下面对其中的一部分做一下引用说明:(书中以jdk 版本号小于50的为例):

java虚拟机规范(SE7)4.10.2.5 异常和 finally  写道
为了实现 try-finally 结构,在版本号小于或等于 50.0 的 Java 语言编译器中,可以使用将两种特殊指令:jsr( “跳转到程序子片段” )和 ret( “程序子片段返回” )组合的方式来生成try-finally 结构的 Java 虚拟机代码。当使用 jsr 指令来调用程序子片段时,该指令会把程序子片段结束后应返回的地址值压入操作数栈中, 以便在 jsr 之后的指令能被正确执行。这个地址值会作为 returnAddress 类型数据存放于操作数栈上。程序子片段的代码中会把返回地址存放在局部变量中,在程序子片段执行结束时,ret 指令从局部变量中取回返回地址并将执行的控制权交给返回地址处的指令。

如果 try 语句中遇到了 return,代码的行为如下:
1. 如果有返回值的话,将返回值保存在局部变量中。
2. 执行 jsr 指令将控制权转到给 finally 语句中。
3. 在 finally 执行完成后,返回事先保存在局部变量中的值。

 

下面再说明另外一个例子:

	public int get() {
		try {
			return 1;
		} finally {
			return 2;
		}
	}

 答案很是奇怪,竟然是2!下面是字节码:

0 goto 4 (+4)
3 pop
4 iconst_2
5 ireturn

 这里有两个return语句,如果按照上面的话第二个return的效果就不会起作用,但是返回的确实是第二个的2!由上面的字节码可以看出,程序直接跳到第二个常量2并返回。

java虚拟机规范在“finally 语句中的代码也给验证器带来了一些特殊的问题”这样写道:

 

验证 finally 语句中的代码是很复杂的,但几个基本的思路如下:
 每个保持追踪 jsr 目标的指令都需要能到达那个目标指令。对于大部分代码来说,这个列表是空的。对于 finally 语句中的代码来说,列表的长度应该是 1。对于多级嵌入finally 代码来说,列表的长度应该大于 1。
 对于每条指令及每条 jsr 指令将要转向到那条指令,在 jsr 指令执行后,就有一个位向量(Bit Vector)记录着所有对局部变量的访问及修改。
 执行 ret 指令就意味着从程序子片段中返回,这应该是唯一的一条从程序子片段中返回的路径。两个不同的程序子片段是不同将 ret 指令的执行结果归并到一起。
 为了对 ret 指令实施数据流分析,需要进行一些特殊处理。因为验证器知道程序子片段中将从哪些指令中返回,所以它可以找出调用程序子片段的所有的 jsr 指令,并将它们对应的 ret 指令的操作数栈和局部变量表状态合并。对于合并局部变量表时使用的特殊值定义如下:
 如果位向量 (前面定义过)表明局部变量在程序子片段中被访问或修改过,那么就使用执行 ret 时局部变量的值的类型。
 对于其它局部变量,使用执行 jsr 指令之前的局部变量的类型。

 

可以看出在java编译对程序进行过优化,优化方法使用数据流分析,将这些局部变量进行了合并,至此,可以看出,在try finally结构含有return的情况,首先根据java编译优化处理,得到字节码,优化主要是对于一些不必要的代码消除合并,如果在try块中含有return则先将return后的变量存在局部变量表中,地址存于操作栈中,然后进入finally块,最后取出局部变量的值返回。如果在finally里有return操作,则把操作栈中的弹出,该return地址入栈,并最后返回。

 

以上不知道我的理解对不对,欢迎讨论!

 

附件是周志明(icyfenix@gmail.com)等人翻译的java虚拟机规范,上文中有引用。

 

 

分享到:
评论

相关推荐

    北京华为经典笔试题(附答案)

    【标题】"北京华为经典笔试题(附答案)"揭示了这是一份关于华为公司在北京进行的笔试环节的试题集,通常包含各种技术性问题,旨在测试应聘者的专业知识和技术能力。华为作为全球知名的电信设备与消费电子产品制造商...

    校招笔试题2014

    【标题】"校招笔试题2014"揭示了这个资料包的主旨,它主要包含的是2014年企业校园招聘时的笔试题目。这些试题通常涵盖多个IT技术领域,旨在测试应聘者的编程能力、逻辑思维、基础知识以及问题解决技巧。对于在校学生...

    中广核在线笔试试题及答案

    第9题是一道简单的逻辑加法题,通过加法运算可以得出甲、丁两班共有86人。 10. 数列构造: 第10题中,每个数是前两个数的乘积加1,因此22之后是155。 11. 三次幂规律: 第11题是三次幂减2的序列,1、2、3、4的三次...

    百度笔试题 百度 笔试题

    【百度笔试题】中的知识点主要涉及三个方面:编程题、算法题和系统设计。下面将分别对这三个方面进行详细的解析。 1. **编程题** 这道编程题要求编写一个函数`is_include(char *a, char *b)`,判断字符串`b`的所有...

    环球雅思的一道笔试题

    有一组字符串,需要对它进行远程读取并按照规则进行逐行排序。 排序规则: 1. 字符规则(注意:区分大小写):j 2. 最后一列(1,2,3,4,5)需出现在排序后的第一列 3. 排序后输出的内容格式保持不变(即两两一组,...

    大疆创新招聘嵌入式笔试题.docx

    【大疆创新嵌入式笔试题】涉及到的IT知识点涵盖了编程基础、嵌入式系统、处理器中断处理、通信协议以及系统设计等多个方面。以下是对这些知识点的详细解释: 1. **编程基础** - **结构体内存占用**:在64位机器上...

    Java经典笔试题

    Java经典笔试题主要涵盖了许多Java基础知识,包括面向对象、异常处理、类与对象、继承、接口、数组、字符串以及Swing组件等。以下是对题目及其涉及知识点的详细解析: 1. 第一道题考察了方法的重写和覆盖。类B继承...

    java经典笔试题

    ### Java经典笔试题详解 #### 一、填空题解析 1. **面向对象的语言具有__继承性__、__封装性__、__多态性__。** - **继承性**:指一个类可以从另一个类派生出来,派生出来的类可以继承父类的属性和方法,并且可以...

    巨人数值策划笔试题(含答案)1

    《数值策划笔试题解析与游戏设计策略》 在IT行业中,尤其是游戏开发领域,数值策划是一项至关重要的工作。它涉及到游戏的经济系统、平衡性以及玩家体验。本文将通过分析几道典型的数值策划笔试题,深入探讨相关知识...

    企业公司软件测试面试笔试题集合 软件测试面试题

    一道测试notepad笔试题.doc 一道数据库的笔试题目.doc 一个外包测试公司的笔试题!.doc 一家通讯公司的面试题目.doc 英文自我介绍大全.doc 英语面试.doc 英语面试题.doc 有意思的逻辑题.doc 中软的面试题(转贴)....

    java 经典笔试题

    【Java经典笔试题详解】 Java作为一门广泛应用的编程语言,其笔试题目往往涵盖了语言特性、设计模式、数据结构与算法、面向对象编程、框架及软件工程等多个方面。以下是对一些常见笔试题目的详细解答: 1. **设计...

    一道笔试题

    标题中的“一道笔试题”可能是指一个编程或技术问题,而描述中提到的“程序员的笔试题”进一步确认了这是一个与编程或IT技术相关的题目。虽然没有提供具体的问题内容,但我们可以通过标签“获取远程数据”来推测这个...

    阿里软件JAVA笔试题

    "阿里软件JAVA笔试题" 阿里软件JAVA笔试题是阿里巴巴公司为招聘软件开发工程师所设计的一份笔试题目,涵盖了JAVA语言、数据结构、算法、设计模式、数据库等多方面的知识点。 本题目共有15道题目,涵盖了以下几个...

    004m金蝶软件测试笔试题回忆版

    ### 004m金蝶软件测试笔试题知识点解析 #### 一、综合类知识点 **1. 职业倾向测试** - **知识点概述**:这类题目旨在评估应试者的个人兴趣、价值观以及性格特点等,从而判断其是否适合从事特定的职业。常见的职业...

    2014美团校招笔试题

    在IT领域,尤其是在招聘过程中,笔试题经常用来评估应聘者的编程和问题解决能力。美团作为一家知名的互联网公司,其校招笔试题往往涉及到算法、数据结构以及概率统计等多个方面。以下将详细解析这些题目所涉及的知识...

    完美世界笔试题.zip

    【完美世界笔试题.zip】是2019年完美世界公司为应聘者准备的...对于“完美世界笔试题”这个压缩文件,解压后应仔细阅读每一道题目,理解其背后的理论,并尝试解答,以此来检验自己的技术水平和提升自己的面试竞争力。

    原创一道Java笔试面试题考考大家

    根据提供的文件信息,我们可以分析出这是一道关于Java继承与方法重写的相关笔试面试题。题目涉及到了Java类的继承、方法重写、实例化对象时的调用顺序以及对象多态性等知识点。接下来,我们将对这些知识点进行详细的...

    趋势科技笔试题(很全很清楚).doc

    这是一道经典的重量判断题,你需要找出唯一一瓶重量不同的药瓶。解答的关键在于利用天平的平衡原理。你可以将五瓶药编号为1~5,然后分别取出1、2、3、4、5颗药丸进行称重。根据差值即可判断出哪一瓶是受污染的。例如...

    软件测试面试和笔试题总汇

    软件测试面试和笔试题总汇中有一道测试的笔试题,输入 a、b、c三个数,如果这三个数满足三角形的条件,则计算三角形的周长,否则输出提示错误。然后判断三角形是等腰三角形还是等边三角形,若是等腰三角形则打印输出...

Global site tag (gtag.js) - Google Analytics