ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从字节码看try catch finally的return如何执行

2020-01-16 18:07:15  阅读:242  来源: 互联网

标签:lang Exception java Utf8 码看 try finally return


文章是对两位博主的总结,提炼,原文如下链接:
从字节码看try catch finally的return如何执行
Java中try catch finally语句中含有return语句的执行情况(总结版)

测试代码很简单,如下:
Test.java

public class Test {
    public int get() {
        try{
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
            return 1;
        } finally {
            return 2;
        }
    }
}

执行$ javap -verbose Test.class

$ javap -verbose Test.class
Classfile /E:/workspace/java/Test.class
  Last modified 2018-1-29; size 405 bytes
  MD5 checksum f8f6002de3931b2e95125679f2ce1f6c
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#17         // java/lang/Object."<init>":()V
   #2 = Class              #18            // java/lang/Exception
   #3 = Methodref          #2.#19         // java/lang/Exception.printStackTrace                          :()V
   #4 = Class              #20            // Test
   #5 = Class              #21            // java/lang/Object
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               get
  #11 = Utf8               ()I
  #12 = Utf8               StackMapTable
  #13 = Class              #18            // java/lang/Exception
  #14 = Class              #22            // java/lang/Throwable
  #15 = Utf8               SourceFile
  #16 = Utf8               Test.java
  #17 = NameAndType        #6:#7          // "<init>":()V
  #18 = Utf8               java/lang/Exception
  #19 = NameAndType        #23:#7         // printStackTrace:()V
  #20 = Utf8               Test
  #21 = Utf8               java/lang/Object
  #22 = Utf8               java/lang/Throwable
  #23 = Utf8               printStackTrace
{
  public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>                          ":()V
         4: return
      LineNumberTable:
        line 1: 0

  public int get();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=4, args_size=1
         0: iconst_0
         1: istore_1
         2: iconst_2
         3: ireturn
         4: astore_1
         5: aload_1
         6: invokevirtual #3                  // Method java/lang/Exception.prin                          tStackTrace:()V
         9: iconst_1
        10: istore_2
        11: iconst_2
        12: ireturn
        13: astore_3
        14: iconst_2
        15: ireturn
      Exception table:
         from    to  target type
             0     2     4   Class java/lang/Exception
             0     2    13   any
             4    11    13   any
      LineNumberTable:
        line 4: 0
        line 9: 2
        line 5: 4
        line 6: 5
        line 7: 9
        line 9: 11
      StackMapTable: number_of_entries = 2
        frame_type = 68 /* same_locals_1_stack_item */
          stack = [ class java/lang/Exception ]
        frame_type = 72 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
}
SourceFile: "Test.java"

直接看重点 Exception table,字节码其他内容不做解释,想了解请移步Class文件格式,并参考JVM字节码手册

      Exception table:
         from    to  target type
             0     2     4   Class java/lang/Exception
             0     2    13   any
             4    11    13   any

JVM8虚拟机规范中的Code属性的标准结构如下:

    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];

看代码就已经比较好理解了:从start_pc(开始的pc指针)执行到end_pc(结束的pc指针),假如发生了catch_type类型的异常,就跳转到异常处理的pc指针处执行(handler_pc)
从0到2执行,要是有java/lang/Exception异常,就跳转到target(目标)4行执行;假如是其他的异常(any),就跳到13行执行;同时发生java/lang/Exception异常后,执行4-11行时假如又发生任意异常(any),就跳到13行执行。
jvm虚拟机就是这样通过异常表来执行的。

因此上述字节码中,有三段重复的字节码执行,带有3个return指令,第一个是没有异常情况下执行的,第二个是我们遇到在catch代码块中指定的异常情况下执行的,第三个是遇到我们未指定的异常情况下执行的。

总结一下,在编译时候,由于JVM没有那么智能,不能像人一样识别finally,因此我们把finally中的代码块放到了try语句块的return之前,并且把try代码块中return的value保存下来,之后根据以下情况(下一段落)来做处理,所以如果未发生异常,那么字节码会顺序执行。如果有异常,那么根据这个异常是否属于在catch中,跳转执行不同的字节码段

try catch finally和return其他状况总结如下:

try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况:

情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。

情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句后,会接着执行try中的return语句,返回之前保留的值。

情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况,:

1)如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。

2)如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。

一只白喵喵 发布了62 篇原创文章 · 获赞 5 · 访问量 4341 私信 关注

标签:lang,Exception,java,Utf8,码看,try,finally,return
来源: https://blog.csdn.net/qq_43186095/article/details/104008375

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有