刚开始学习java的时候,finally,return是个头疼的问题,面试题里天天都是问谁先执行?
下面我们就结合《深入java虚拟机》第18章 finally子语句和例子对应的字节码来探讨一下这个问题
看此篇文章之前可以看看前面一篇文章描述finally字节码:
http://abc08010051.iteye.com/admin/blogs/2154981
例子1:
public static int tt1() { int b = 23; try { System.out.println("yes"); return b += 88; } catch (Exception e) { System.out.println("error : " + e); } finally { if (b > 25) { System.out.println("b>25 : " + b); } System.out.println("finally"); } return b; }
代码执行结果:
yes b>25 : 111 finally 111
bytecode:
bipush 23 //把23压入栈 istore_0 //把23放到位置为0的局部变量中 getstatic java/lang/System/out Ljava/io/PrintStream; ldc "yes" //把常量“yes”压入栈 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //打印"yes" iinc 0 88 //位置为0的变量值加88 iload_0 //把位置为0的局部变量(值为111)压入栈 istore_1 //把栈顶元素出栈,(栈顶元素为111),并赋值给位置为1的局部变量 iload_0 //把位置为0的局部变量值压入栈 bipush 25 //把25压入栈 if_icmple 22 //比较栈顶两个int类型的值,如果小于0调到22执行 getstatic java/lang/System/out Ljava/io/PrintStream; //此行到22行,通过StringBuilder构建字符串"b>25 : "加上b(即位置为0的局部变量值),并打印字符串 new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //从11行到此行,通过StringBuilder构建字符串"b>25 : "加上b(即位置为0的局部变量值),并打印字符串 getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //打印“finally”字符串 iload_1 //获取位置为1的局部变量的值并压入栈中 ireturn //返回栈顶的int值 astore_1 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "error : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; aload_1 invokevirtual java/lang/StringBuilder/append(Ljava/lang/Object;)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V iload_0 bipush 25 if_icmple 51 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V goto 74 astore_2 iload_0 bipush 25 if_icmple 69 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V aload_2 athrow iload_0 ireturn//对应代码最后的return
上面的字节码值解释了我们方法正常执行的部分,由上面的字节码解释我们知道:return语句时在finally例程执行之后才执行的
例子2:
这个例子和上面的那个差不多,差别是在finally语句块里对变量进行了操作:
public static int tt2() { int b = 23; try { System.out.println("yes"); return b += 88; } catch (Exception e) { System.out.println("error : " + e); } finally { if(b>25) { System.out.println("b>25 : "+b); } System.out.println("finally"); b = 100; } return b; }执行结果:
yes b>25 : 111 finally 111这个结果很令人诧异,如果按照例子1得出来的结论,return 在finally语句块之后执行,那么输出结果应该是:
yes b>25 : 111 finally 100
这是为什么呢?
我们来看看tt2()方法的字节码:
bipush 23 //把23压入栈 istore_0 //把23放到位置为0的局部变量中 getstatic java/lang/System/out Ljava/io/PrintStream; ldc "yes" //把常量“yes”压入栈 invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //打印"yes" iinc 0 88 //位置为0的变量值加88 iload_0 //把位置为0的局部变量(值为111)压入栈 istore_1 //把栈顶元素出栈,(栈顶元素为111),并赋值给位置为1的局部变量 iload_0 //把位置为0的局部变量值压入栈 bipush 25 //把25压入栈 if_icmple 22 //比较栈顶两个int类型的值,如果小于0调到22执行 getstatic java/lang/System/out Ljava/io/PrintStream; //此行到22行,通过StringBuilder构建字符串"b>25 : "加上b(即位置为0的局部变量值),并打印字符串 new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //从11行到此行,通过StringBuilder构建字符串"b>25 : "加上b(即位置为0的局部变量值),并打印字符串 getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V //打印“finally”字符串 bipush 100 //把100压入栈顶 istore_0 //把栈顶值(100)弹出栈,并赋值给位置为0的局部变量(代码中的b) iload_1 //把位置为1的局部变量(111)压入栈 ireturn //弹出栈顶的int值,返回,退出方法 astore_1 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "error : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; aload_1 invokevirtual java/lang/StringBuilder/append(Ljava/lang/Object;)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V iload_0 bipush 25 if_icmple 53 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V bipush 100 istore_0 goto 80 astore_2 iload_0 bipush 25 if_icmple 73 getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder dup invokespecial java/lang/StringBuilder/<init>()V ldc "b>25 : " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; iload_0 invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "finally" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V bipush 100 istore_0 aload_2 athrow iload_0 ireturn
从上面的字节码可以看出,return还是在finally语句块之后执行, 返回111而不是100的原因可以参考上面标注为红色的bytecode解释,
当代码执行到“return b += 88;” 这一行时,jvm把局部变量b加88,加后的局部变量b存放在位置为0的变量中,然后把b的值复制存放到位置为1的局部变量中,
执行finally语句块时,对局部变量b进行操作,在虚拟机内部只是对位置为0的变量进行操作,当返回时,虚拟机返回的是位置为1的变量值,即为111
深入java虚拟机也有此解释:
例子3:
public static int tt3() { int b = 23; try { System.out.println("yes"); return b += 88; } catch (Exception e) { System.out.println("error : " + e); } finally { if(b>25) { System.out.println("b>25 : "+b); } System.out.println("finally"); b = 100; return b; } }执行结果:
yes b>25 : 111 finally 100根据结果判断,在执行“return b += 88;”这行代码的时候,把表达式“b += 88;”执行以后去执行finally语句块执行,在finally语句中return,退出方法
相关推荐
java虚拟机的运行机理的详细介绍 Inside the Java Virtual Machine Bill Venners $39.95 0-07-913248-0 Inside the Java Virtual Machine Acknowledgments Introduction Part One: Java's Architecture 1 ...
1.2 Java虚拟机 ................................................... 18 1.3 各章节提要 ..................................................... 19 1.4 说明 ....................................................
1.2 Java虚拟机 ................................................... 18 1.3 各章节提要 ..................................................... 19 1.4 说明 ....................................................
## 二.finally finally 一定会被执行,如果 finally ...finalize()方法是Object类的一个protected方法,它是在对象被垃圾回收之前由Java虚拟机来调用的。 ## 四. finally到底是在return之前执行还是return之后执行?
1.5.4 Java虚拟机(Java Virtual Machine) 17 1.5.5 HelloWorld的整个流程 17 1.6 小结:我们学会了编译和运行一个Java程序! 18 1.7 习题 19 第2章 搭建自己的集成开发环境 20 教学视频:31分钟 2.1 安装...
return javacount; } public void setJavaUseMemory(double javaUseMemory) { this.javaUseMemory = javaUseMemory; } public double getJavaUseMemory() { return javaUseMemory; } } import java....
1.5.4 Java虚拟机(Java Virtual Machine) 17 1.5.5 HelloWorld的整个流程 17 1.6 小结:我们学会了编译和运行一个Java程序! 18 1.7 习题 19 第2章 搭建自己的集成开发环境 20 教学视频:31分钟 2.1 安装...
学生提问:不是说JVM是运行Java程序的虚拟机吗?那JRE和JVM的关系是怎样的呢? 8 学生提问:为什么不安装公共JRE系统呢? 9 1.4.2 设置PATH环境变量 10 学生提问:为什么选择设置用户变量,用户变量和系统变量有...
35.java除了8种基本类型外,在虚拟机里还有哪一种,有什么作用? 36.除了使用new关键字创建对象意外,试列举另外三种以上创建实例的方式? 37.classloader中,JDK的API、Classpath中的同web-inf中的class加载方式有...
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...
77.2. 修改java虚拟机内存 88 77.3. 修改tomcat连接数 88 77.4. 禁止列出目录下的文件 88 77.5. 设置session失效的时间 89 77.6. 设置MIME响应类型 89 77.7. 设置tomcat的默认访问页面 89 77.8. 设置tomcat管理用户 ...
38、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 25 39、下面的程序代码输出的结果是多少? 25 40、final, finally, finalize的区别。 27 ...
38、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 25 39、下面的程序代码输出的结果是多少? 25 40、final, finally, finalize的区别。 27 ...
81、public class Something { public int addOne(final int x) { return ++x; }}这个比较明显。 19 83、class Something { int i; public void doSomething() { System.out.println("i = " + i); }} 有什么错呢? 19...
38、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 25 39、下面的程序代码输出的结果是多少? 25 40、final, finally, finalize的区别。 27 ...
是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。 ####2.一只蜗牛掉进10米深的井中。白天往上爬4米晚上又掉下去3米。请问要几天才能爬出来井口? 7天。 计算: 6*(4-3)+4=10 ###...
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...
38、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 39、下面的程序代码输出的结果是多少? 40、final, finally, finalize的区别。 41、...