直接进入主题。看如下代码:

public int test(){
int i=0;
try {
i=1;
return i;
} catch (Exception e) {
i=2;
return i;
}finally{
i=3;
}
}

相信有点经验的程序员一眼就能说出返回的结果为1,但是您真的知道返回的结果为什么为1吗?下面我们通过分析下当前方法的字节码,来说明为什么。

查看字节码命令:javap -verbose class文件

知识点简单概要:
看如下字节码需要简单了解下栈的结构。
栈包括:局部变量表、操作数栈、动态连接、方法出口等。
下面字节码主要是对操作栈和局变量表的操作。

test方法的字节码如下:

 stack=1, locals=5, args_size=1
0: iconst_0 将常量0压入到操作栈顶
1: istore_1 将栈顶元素0存储到局部变量表中的第二个slot中 (slot2=0) i=0
2: iconst_1 将常量1压入到操作栈顶
3: istore_1 将栈顶元素1存储到局部变量表中的第二个slot中 (slot2=1) i=1
4: iload_1 将局部变量中第二个变量 (i=1) 压入到操作栈顶
5: istore 4 将栈顶元素1存储到局部变量表中的第四个slot中 (slot4=1)
7: iconst_3 将常量3压入到操作栈顶
8: istore_1 将栈顶元素3存储到局部变量表中的第二个slot中 (slot2=1) i=3
9: iload 4 将局部变量中第四个变量 (slot4=1) 压入到操作栈顶
11: ireturn 返回操作栈顶值,这时操作栈中栈顶值为1。
12: astore_2 将栈顶元素(e)存储到局部变量表的第三个slot中
13: iconst_2 将常量2压入到操作栈顶
14: istore_1 将栈顶元素2存储到局部变量表中的第二个slot中 (slot2=2) i=2
15: iload_1 将局部变量中第二个变量 (i=2) 压入到操作栈顶
16: istore 4 将栈顶元素2存储到局部变量表中的第四个slot中 (slot4=2)
18: iconst_3 将常量3压入到操作栈顶
19: istore_1 将栈顶元素3存储到局部变量表中的第二个slot中 (slot2=1) i=3
20: iload 4 将局部变量中第四个变量 (slot4=2) 压入到操作栈顶
22: ireturn 返回操作栈顶值,这时操作栈中栈顶值为2。
23: astore_3 将栈顶元素(其它异常,Exception之外的)存储到局部变量表的第四个slot中
24: iconst_3 将常量3压入到操作栈顶
25: istore_1 将栈顶元素3存储到局部变量表中的第二个slot中 (slot2=3) i=3
26: aload_3 将局部变量中第四个变量 (其它异常) 压入到操作栈顶
27: athrow 抛出栈顶元素(异常信息) 无返回值

stack=1, locals=5, args_size=1

  • stack=1:操作栈的深度
  • locals=5:局部变量表中5个slot(槽位),每个slot存储能一个变量(long、double 需要两个slot存储)
    1. this变量
    2. i 变量
    3. e 变量(Exception)
    4. Exception之外异常的变量
    5. 临时存储变量(返回值从临时存储中返回的)
  • args_size=1: 方法的参数个数(该方法无参数,为什么这里args_size为1呢?因为这个是实例方法,不是静态方法,他默认会传过来当前实例的引用,也就是this变量)

字节码执行路径

通过字节码我们发现在编译成class文件的时候,已经把三种执行路径都写到class文件中了。

  1. 第一种路径
    第【1-11】行,程序正常执行顺序(无异常)
  2. 第二种路径
    第【12-22】行,程序报Exception的异常
  3. 第三种路径
    第【23-27】行,程序报Exception之外的异常

字节码大白话解释说明

第[0-1]行,代码:int i=0;
第[2-3]行,try块中代码:i=1;
第[4-5]行,遇到return时,把 i 的值临时存储起来,然后执行finally中的代码。
第[7-8] 行,finally块代码:i=3
第[9-11] 行,执行return语句,把临时存储的 i 值返回。(执行finally代码对返回值无影响)
第[12]行,catch块代码: (Exception e)
第[13-14]行,catch块代码: i=2
第[15-16]行,遇到catch块中的return时,把 i 的值临时存储起来,然后执行finally中的代码。
第[18-19]行,finally块代码:i=3
第[20-22]行,执行catch块中return语句,把临时存储的 i 值返回。(执行finally代码对返回值无影响)
第[23]行,局部变量表中存储Exception之外的异常
第[24-25]行,finally块代码:i=3
第[26-27]行,将Exception之外的异常压入栈顶,并抛出(无返回值)

结论

通过字节码,我们发现,在try语句的return块中,return 返回的变量并不是直接返回 i 值,而是在执行finally块之前把i值存储在临时区域,当执行return时直接返回的临时区域中的值,即使在finally语句中把变量 i 的值修改了,也不会影响返回的值。

字节码分析finally块对return返回值的影响的更多相关文章

  1. Java字节码分析

    目录 Java字节码分析 查看字节码详细内容 javap 实例分析 Java字节码分析 对于源码的效率,但从源码来看有时无法分析出准确的结果,因为不同的编译器版本可能会将相同的源码编译成不同的字节码, ...

  2. JVM-String比较-字节码分析

    一道String字符串比较问题引发的字节码分析 public class a { public static void main(String[] args)throws Exception{ } p ...

  3. Python_Tips[2] -> 函数延后估值及字节码分析

    函数延后估值及字节码分析 在一个循环中定义了函数 f 但是并未对其进行调用,在循环结束后调用,此时i值为3故最终3个函数输出均为9.而非1, 4, 9. 这是由于在定义闭包函数 f 时,传入变量 i, ...

  4. HDFS源码分析数据块校验之DataBlockScanner

    DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...

  5. Java并发编程原理与实战八:产生线程安全性问题原因(javap字节码分析)

    前面我们说到多线程带来的风险,其中一个很重要的就是安全性,因为其重要性因此,放到本章来进行讲解,那么线程安全性问题产生的原因,我们这节将从底层字节码来进行分析. 一.问题引出 先看一段代码 packa ...

  6. 通过字节码分析java中的switch语句

    在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...

  7. 通过字节码分析Java方法的静态分派与动态分派机制

    在上一次[https://www.cnblogs.com/webor2006/p/9723289.html]中已经对Java方法的静态分派在字节码中的表现了,也就是方法重载其实是一种静态分派的体现,这 ...

  8. 通过字节码分析this关键字以及异常表的重要作用

    在之前的字节码分析中缺少对异常的介绍,这次主要来对字节码异常表相关的东东进行一个学习,下面先来编写一个相关异常的小程序: 接着编译来看用javap -verbose来查看一下它的字节码信息: xion ...

  9. HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

    HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

随机推荐

  1. How to Auto Execute Commands/Scripts During Reboot or Startup.

    https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/installation_guide/s1- ...

  2. oracle sql合计结果信息使用分组的小问题

    --月统计 Select SUBSTR(t.BalanceDate,1,6) as Mon, t.RechargeType , SUM(t.SumNum) as SumNum , SUM(t.SumF ...

  3. numpy数组-标准化数据

    标准化数据的公式: (数据值 - 平均数) / 标准差 import numpy as np employment = np.array([ 55.70000076, 51.40000153, 50. ...

  4. Python args **kwargs作用

    python当函数的参数不确定时,可以使用*args和**kwargs,*args用于捕获所有no keyword参数,它是一个tuple.**kwargs捕获所有keyword参数,它是一个dict ...

  5. 碰撞器与触发器[Unity]

    请看原帖,移步:Unity3d碰撞检测中碰撞器与触发器的区别 要产生碰撞必须为游戏对象添加刚体(Rigidbody)和碰撞器,刚体可以让物体在物理影响下运动.碰撞体是物理组件的一类,它要与刚体一起添加 ...

  6. ZendStudio在kali下无法启动

    错误如下 # # A fatal error has been detected by the Java Runtime Environment: # #  SIGSEGV (0xb) at pc=0 ...

  7. iOS高版本备份恢复到低版本系统的方法

    一般来说,在更新iOS系统的时候我们都会建议大家先用iTunes对系统进行完整备份.但时不时都会有人偷懒,或者使用手机OTA升级而没有对系统备份,最终导致不满意新系统了,想降级却无备份可以恢复的尴尬局 ...

  8. apache ab压力测试报错apr_socket_recv

    apache ab压力测试报错(apr_socket_recv: Connection reset by peer (104)) apache 自带的ab工具测试,当并发量达到1000多的时候报错如下 ...

  9. pandas简单应用

    机器学习离不开数据,数据分析离不开pandas.昨天感受了一下,真的方便.按照一般的使用过程,将pandas的常用方法说明一下. 首先,我们拿到一个excel表,我们将之另存为csv文件.因为文件是实 ...

  10. poj2965(位运算压缩+bfs+记忆路径)

    题意:有个4*4的开关,里面有着16个小开关 -+-- ---- ---- '+'表示开关是关着的,'-'表示开关是开着的,只有所有的开关全被打开,总开关才会被打开.现在有一种操作,只要改变某个开关, ...