`

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

    博客分类:
  • java
阅读更多

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

 

public class App {
    
    public String getName(String name){
        String res="";
        try {
            res=name;
            return res;
        }finally {
            res="zhangsan";
        }
    }

    public static void main(String[] args) throws InterruptedException {
        App app=new App();
        String name=app.getName("wangwu");
        System.out.println(name);

    }
}

//结果:wangwu

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

 

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

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

 

public java.lang.String getName(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=5, args_size=2
         0: ldc           #2                  // String
         2: astore_2
         3: aload_1
         4: astore_2
         5: aload_2
         6: astore_3
         7: ldc           #3                  // String zhangsan
         9: astore_2
        10: aload_3
        11: areturn
        12: astore        4
        14: ldc           #3                  // String zhangsan
        16: astore_2
        17: aload         4
        19: athrow
      Exception table:
         from    to  target type
             3     7    12   any
            12    14    12   any
      LineNumberTable:
        line 16: 0
        line 18: 3
        line 19: 5
        line 21: 7
        line 19: 10
        line 21: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      20     0  this   Lcom/qlteacher/App;
            0      20     1  name   Ljava/lang/String;
            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

上面这两个个命令就是对应  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未改变,

 

 

 

 

 

 

 

3
0
分享到:
评论
2 楼 z19910509 2017-08-08  
bmd360 写道

什么多少分
1 楼 bmd360 2017-08-07  

相关推荐

    java finally块执行时机全面分析

    关于字节码层面的解释,根据《深入Java虚拟机》一书的描述,`finally`块的实现是通过`jsr`(Jump to Subroutine,跳转到子例程)指令来实现的。这个指令使得JVM能够调转到`finally`块执行,然后在`finally`块执行...

    AtividadesJava:Java执行顺序

    描述中的“Sequência de exercícios em Java”进一步确认了这是关于Java编程中的执行顺序问题,这通常涉及到程序控制流的概念,如顺序执行、条件判断和循环。 在Java中,程序的执行顺序遵循一定的规则: 1. **源...

    java面试必备_初级java工程师_java开发

    - **JVM** (Java Virtual Machine) 是一个能够执行编译后的Java字节码的虚拟机环境。它提供了一个平台无关的运行环境,使得Java程序可以在任何安装了JVM的平台上运行。 - **加载Class文件原理**:在Java中,类的...

    java语言基本语法.docx

    * 顺序结构:顺序执行语句 * 选择结构:if语句、switch语句 * 循环结构:while语句、for语句、do-while语句 * 跳转结构:break语句、continue语句、return语句 方法 Java语言中有两种方法:实例方法和静态方法。...

    Java软件开发实战 Java基础与案例开发详解 2-4 java类库组织结构和文档 共9页.pdf

    - **Java 虚拟机(JVM)**:解释和执行Java字节码的虚拟机。 - **垃圾回收机制**:自动管理内存,释放不再使用的对象所占用的空间。 - **MyEclipse 工具**:一款集成开发环境(IDE),用于Java应用程序的开发。 - **数据...

    java面试题基础篇

    在 Java 中,`try-finally` 结构中的 `finally` 块总会被执行,即使 `try` 块中有 `return` 语句也不例外。具体来说: - 如果 `try` 块中有 `return` 语句,那么 `finally` 块会在 `return` 语句执行之后、返回值...

    Java软件开发实战 Java基础与案例开发详解 10-9 练习题 共5页.pdf

    Java程序通过编译器转换为字节码,然后由Java虚拟机(JVM)解释执行。 #### 2.3 Java程序 Java程序是由多个类组成,这些类通过继承、封装等机制相互关联。 #### 2.4 Java类库组织结构和文档 Java提供了丰富的标准...

    java 试题6

    4. **Java的结构中立性**:Java源代码编译成字节码,这是一种结构中立的目标文件格式,可以在任何支持Java的平台上运行,无需重新编译。选项C正确地阐述了这一特性,展示了Java的“一次编写,到处运行”理念。 5. *...

    Java软件开发实战 Java基础与案例开发详解 14-8 练习题 共6页.pdf

    Java虚拟机(JVM)是Java程序的运行环境,负责解释执行Java字节码。它包括类加载器、运行时数据区、执行引擎等组件。 #### 2.6 Java的垃圾回收器 Java自动管理内存,通过垃圾回收机制自动回收不再使用的对象所占用...

    java核心技术 卷一(第9版).pdf

    Java源代码在编译后会被转换成字节码,由JVM执行,这为Java带来了平台无关的特性。 2. Java数据类型和变量 Java的数据类型分为基本数据类型和引用数据类型。基本数据类型包括数值型(整数、浮点数)、字符型和布尔...

    Java试题及答案[归类].pdf

    - **解析:** Java 源代码文件(.java)编译后会生成字节码文件(.class),这些字节码文件可以在支持 Java 的平台上通过 JVM 执行。字节码是一种中间语言,它不是机器代码,而是 JVM 能够理解的指令集。 3. **题目:** ...

    Java语言程序设计试卷D卷.pdf

    选项中的`javac`是Java编译器的命令,用于将Java源代码文件编译成字节码文件(.class文件)。因此,正确答案是A。 ### 2. Java 语言的独特特性 第二个问题提到了Java语言的一些特点,并询问这些特点中哪一个不是...

    java面试题目大全

    - **程序计数器**:程序计数器是一块较小的内存空间,当前线程所执行的字节码的行号指示器。线程私有,每条线程都有自己的程序计数器。 - **本地方法栈**:本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别...

    2018阿里Java面试题70道

    33. **return与finally**:return执行后,finally块仍会执行,但return的结果不会改变。 34. **try-catch-finally执行顺序**:try先执行,如有异常则跳转至catch,最后执行finally。 35. **Java数据类型**:分为...

    java程序设计实践教程

    - JVM是执行Java字节码的虚拟机,其安装通常与SDK一起完成。 - 确认JVM版本与操作系统兼容。 - **使用JCreator:** - JCreator是一款轻量级的Java IDE,适合初学者。 - 学习如何在JCreator中创建项目、编写代码...

    Java笔试题集.pdf

    1. 字节码文件扩展名:Java源代码经过编译后生成的是字节码文件,其扩展名为`.class`(对应题目第1题答案B)。这些字节码文件可以在任何支持Java的平台上运行,因为Java采用了“一次编写,到处运行”的理念。 2. ...

    java资料面试题

    3. **加载与解释执行**:Java 虚拟机 (JVM) 加载字节码文件,并将其解释执行。 #### 1.7 什么是 JVM?有什么作用?工作机制如何? **JVM (Java Virtual Machine)** 是 Java 程序的运行环境,它是一个抽象的计算机...

    2021 java面试题.pdf

    JDK动态代理基于接口,CGLIB动态代理通过字节码技术创建代理类,适用于没有接口的情况。 Java IO中,流分为字节流和字符流,序列化用于持久化对象,字节流和字符流主要区别在于处理单元,PrintStream等流类用于格式...

    java面试宝典

    29. **Return和finally语句块的顺序**:finally块先于return执行。 30. **Java静态变量与实例变量的区别**:静态变量属于类,实例变量属于对象。 31. **String为什么是final**:为了安全性和性能优化。 32. **Java...

Global site tag (gtag.js) - Google Analytics