热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从字节码看trycatchfinally的return如何执行

文章是对两位博主的总结,提炼,原文如下链接:从字节码看trycatchfinally的return如何执行Java中trycatchfinally语句中含有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.classLast modified 2018-1-29; size 405 bytesMD5 checksum f8f6002de3931b2e95125679f2ce1f6cCompiled from "Test.java"
public class Testminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref #5.#17 // java/lang/Object."":()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 // "":()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: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object." ":()V4: returnLineNumberTable:line 1: 0public int get();descriptor: ()Iflags: ACC_PUBLICCode:stack=1, locals=4, args_size=10: iconst_01: istore_12: iconst_23: ireturn4: astore_15: aload_16: invokevirtual #3 // Method java/lang/Exception.prin tStackTrace:()V9: iconst_110: istore_211: iconst_212: ireturn13: astore_314: iconst_215: ireturnException table:from to target type0 2 4 Class java/lang/Exception0 2 13 any4 11 13 anyLineNumberTable:line 4: 0line 9: 2line 5: 4line 6: 5line 7: 9line 9: 11StackMapTable: number_of_entries = 2frame_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 type0 2 4 Class java/lang/Exception0 2 13 any4 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中改变后的该属性的值。


推荐阅读
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 【技术分享】一个 ELF 蠕虫分析
    【技术分享】一个 ELF 蠕虫分析 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • 精讲代理设计模式
    代理设计模式为其他对象提供一种代理以控制对这个对象的访问。代理模式实现原理代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色ÿ ... [详细]
  •  项目地址https:github.comffmydreamWiCar界面做的很难看,美工方面实在不在行。重点是按钮触摸事件的处理,这里搬了RepeatListener项目代码,例 ... [详细]
  • 【CTF 攻略】第三届 SSCTF 全国网络安全大赛—线上赛 Writeup
    【CTF 攻略】第三届 SSCTF 全国网络安全大赛—线上赛 Writeup ... [详细]
author-avatar
娇Rex_630
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有