路人战队 授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码( 五 )


字节码分析 , 从上面的方法属性表位置开始:
路人战队 授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码
文章图片
attribute_name_index是一项指向CONSTANT_UTF8_INFO的常量索引 , 常量值固定为Code,代表了该属性的属性名称 。
看一段包含异常语法的简单代码:
/***@authorbyzengzhiqin*2020-09-13*/publicclassTestException{publicintinc(){intx;try{x=1;returnx;}catch(Exceptione){x=2;returnx;}finally{x=3;}}}复制代码再看其内容(字节码0~4行做的就是将证书1赋值给变量x,并且将x的值复制一份副本到最后一个本地变量表的slot中 , 这个slot里面的值在ireturn指令执行前将会被重读到操作栈顶 , 作为方法返回值使用 , 这个slot用returnValue表示):
0:iconst_0//常量0压入操作数栈1:istore_2//弹出操作数栈栈顶元素 , 保存到局部变量表第2个位置2:iload_0//第0个变量压入操作数栈顶3:iload_1//第1个变量压入操作数栈顶4:iadd//操作数栈中的前两个int相加 , 并将结果压入操作数栈顶5:istore_2//弹出操作数栈栈顶元素 , 保存到局部变量表第2个位置6:iload_2//加载局部变量表的第2个变量到操作数栈顶7:ireturn//返回8:aload//从局部变量表的相应位置装载一个对象引用到操作数栈的栈顶复制代码上面是一些需要用的的指令的相关解释
zengzhiqin@cengzhiqindeMacBook-Pro?~/Desktop/daima/leetcode/ src?javap-cTestExceptionCompiledfrom"TestException.java"publicclassTestException{publicTestException();Code:0:aload_01:invokespecial#1//Methodjava/lang/Object."":()V4:returnpublicintinc();Code:0:iconst_1//try中x=1,1压入操作数栈1:istore_1//将1从操作数栈存储到局部变量表第一个位置,x=12:iload_1//加载局部变量表第一个位置元素到操作数栈顶3:istore_2//弹出操作数栈顶元素1 , 保存到局部变量表第2个位置4:iconst_3//finally块中x=3 , 将3压入操作数栈5:istore_1//弹出栈顶元素3 , 将其保存到局部变量表第1个位置6:iload_2//将变量表第2个位置值1放到栈顶 , 准备给ireturn返回7:ireturn//正常情况下返回1正确吻合~8:astore_2//给catch中定义的Exceptione赋值 , 存储在slot2中9:iconst_2//catch中x=2 , 2压入操作数栈10:istore_1//弹出栈顶的2 , 保存到slot111:iload_1//局部变量表第1个位置的2压入栈顶12:istore_3//弹出栈顶元素2保存到局部变量第3个位置13:iconst_3//finally中x=3 , 将3压入操作数栈14:istore_1//将3放到局部变量表第1个位置 , 准备给ireturn返回15:iload_3//加载局部变量表第3个位置的值2到栈顶16:ireturn//返回栈顶元素2catch异常返回2正确 , 吻合17:astore4//如果出现了不属于java.lang.Exception及其子类异常走到这里19:iconst_3//finally块中x=3 , 将3压入操作数栈20:istore_1//将3存储到局部变量表第1个位置21:aload4//将异常引用放在栈顶 , 并且抛出23:athrow//抛出异常Exceptiontable:fromtotargettype048Classjava/lang/Exception0417any81317any171917any}复制代码这里可初步推测 , Java虚拟机执行字节码是基于栈的体系结构 , 执行过程可以看我上一篇的讲解~懒得贴链接了 。
异常的执行过程 , finally代码块会在所有正常及异常的路径上都复制一份 , 在这段字节码中 , iconst_3就是对应着finally代码块 , 共三份 , 所以即便在try或者catch代码块中有return语句 , 最终还是会会执行finally代码块中的内容 , 这段代码毫无疑问是返回1 , 如果在finally里面加上returnX,那么就是返回3了 , 这个return什么值的原因是这样来滴!!!
我们可以看到异常表 , 归纳出异常表结构:
路人战队 授人以鱼不如授人以渔,软妹手把手教你javap反编译分解代码
文章图片
字节码0-4行所做的操作数就是将整数1赋值给变量x如果这时没有出现异常 , 则会继续走到第5-7行如果出现了异常 , PC寄存器指针转到第8行如果0-4行出现任何异常 , 则跳转17行如果8-13行出现任何异常 , 则跳转17行如果17-19行出现任何异常 , 则跳转17行可知 , 异常表实际上是JAVA代码的一部分 , 编译器使用异常表而不是简单命令来实现JAVA异常以及finally处理机制的 。


推荐阅读