java中return与finally的执行顺序分析(根据字节码分析)

大家应该都知道,在java中无论是否出异常,finally中的代码都会被执行的,所以我们经常在里面做些释放连接的工作。 但如果有返回值,return与finally是怎么样执行的呢?首先看下面代码。

 

Java代码   收藏代码
  1. public class App {  
  2.       
  3.     public String getName(String name){  
  4.         String res="";  
  5.         try {  
  6.             res=name;  
  7.             return res;  
  8.         }finally {  
  9.             res="zhangsan";  
  10.         }  
  11.     }  
  12.   
  13.     public static void main(String[] args) throws InterruptedException {  
  14.         App app=new App();  
  15.         String name=app.getName("wangwu");  
  16.         System.out.println(name);  
  17.   
  18.     }  
  19. }  
  20.   
  21. //结果:wangwu  

下面我们根据生成的字节码来分析下为什么出现这个结果。

 首先官网:www.fhadmin.org 进入这个类生成的App.class文件目录,执行命令:javap -c -verbose App

这样就打印出了这个类的字节码信息。下面贴一下我们本次分析需要的内容。

 

Java代码   收藏代码
  1. public java.lang.String getName(java.lang.String);  
  2.     descriptor: (Ljava/lang/String;)Ljava/lang/String;  
  3.     flags: ACC_PUBLIC  
  4.     Code:  
  5.       stack=1, locals=5, args_size=2  
  6.          0: ldc           #2                  // String  
  7.          2: astore_2  
  8.          3: aload_1  
  9.          4: astore_2  
  10.          5: aload_2  
  11.          6: astore_3  
  12.          7: ldc           #3                  // String zhangsan  
  13.          9: astore_2  
  14.         10: aload_3  
  15.         11: areturn  
  16.         12: astore        4  
  17.         14: ldc           #3                  // String zhangsan  
  18.         16: astore_2  
  19.         17: aload         4  
  20.         19: athrow  
  21.       Exception table:  
  22.          from    to  target type  
  23.              3     7    12   any  
  24.             12    14    12   any  
  25.       LineNumberTable:  
  26.         line 160  
  27.         line 183  
  28.         line 195  
  29.         line 217  
  30.         line 1910  
  31.         line 2112  
  32.       LocalVariableTable:  
  33.         Start  Length  Slot  Name   Signature  
  34.             0      20     0  this   Lcom/qlteacher/App;  
  35.             0      20     1  name   Ljava/lang/String;  
  36.             3      17     2   res   Ljava/lang/String;  

 首先解释下各个命令:

 

ldc:将int,float或者String类型常量从常量池推送至栈顶。

astore:将栈顶引用型类型数据存入指定本地变量。

aload:将制定的引用类型变量推送至栈顶

 

方法的简要执行:

在jvm中,每个线程都具有自己的虚拟机栈。当执行方法时,如上面的getName,就会创建一个栈帧(存储局部变量表,操作数栈等信息)进入虚拟机栈。每一个方法从调用到执行完毕,就是一个栈帧从虚拟机栈中入栈到出栈的过程。

 

下面分析下字节码:

 

首先看这行:

stack=1, locals=5, args_size=2,根据这行提示我们能知道这个方法栈的深度为1,局部变量表里有5个数值,参数大小为2.

但我们这个方法getName(String name)只有一个方法啊,哪来的两个。因为对于实例方法,编译器会默认添加一个参数:this,代表对当前实例的引用。这就是我们能在代码中使用this. 的原因。

 

0: ldc           #2 

2: astore_2

上面这两个个命令就是对应 String res="";

首先ldc命令,将常量池中对应 #2(常量池代码没有贴上来)也就是 "",放入操作数栈。

然后将操作数栈数据出栈,并且存入局部变量表的下标为2的slot中。(为什么存入第三个呢,因为第一个是上面说的this,第二个是方法的参数name)

 

3: aload_1

 

4: astore_2

上面这两个官网:www.fhadmin.org 个命令就是对应  res=name;

首先aload_1是将局部变量表中的第二个数值(也就是我们的参数name)取出来放入操作数栈

然后astore_2 将刚才的数出栈并且存入局部变量表的第三个位置,也就是上面res的位置,这样就完成了将name的值赋给了res。

 

5: aload_2

 

6: astore_3

代码继续执行,不出异常的话就因该执行return res;这句代码了

当执行到这句代码的时候,首先从局部变量表第三个位置(res变量)取出res的数值放入操作数栈顶。然后出栈放入操作数栈的第四个位置(为了方便,我们暂且给它起个名字为returnValue)。

通过上面命令这个方法需要返回的值就已经确定并存储好了。

 

7: ldc           #3                  // String zhangsan

 

9: astore_2

这两句就是finally中的语句了。

首先将常量池对应 #3的常量(zhangsan)压入操作数栈。然后将这个数出栈astore_2并且存入局部变量表的第三个位置(res),这样就完成了res="zhangsanj";需要注意的是此时虽然改了res,但我们上面所存放的returnValue值还未改变

 

10: aload_3

 

11: areturn

这两步就是return操作了,将局部变量表中第四个位置的数值(上面的returnValue)压入操作数栈,然后返回。

 

到这里,这个方法就执行完了。后面的代码是异常分支,当出现异常的时候会走下面的代码,这里不再分析。

 

总结:

当执行代码碰到return的时候,会将要返回的值存入局部变量表(暂且起名为returnValue)。如果有finally代码块,就会执行finally中的代码,执行完毕后,取出returnValue中的内容,进行反回。

 

上面代码中res作为返回值,但res变量本身与返回值存放在不同的位置,所以后期改了res后,returnValue未改变,

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值