Java字节码介绍【三】

本文为翻译的文章,作者Mahmoud Anouti,原文:
https://dzone.com/articles/introduction-to-java-bytecode

方法调用:

在之前的示例中,仅有一个main方法。假设我们需要对于变量c做更精细的计算,我们决定把它放在一个新的方法中,名字是calc:
在这里插入图片描述
让我们看看生成的字节码:
在这里插入图片描述
main方法代码的唯一区别是:我们不是使用iadd指令,而是invokestatic指令,它调用了静态方法calc。需要注意的关键点是,操作数栈包含了两个传递给calc方法的参数。换句话说,调用方法准备好所有被调方法需要的参数,把这些参数以正确的顺序加入操作数栈顶。invokestatic(或者一个我们在后面会看到的相似的调用指令)接下来会把这些参数出栈,一个新的为被调用方法准备的栈帧会被创建,参数会放置在它的局部变量数组中。

通过观察地址信息,我们也注意到invokestatic指令占用了3个字节,从6跳到了9。这是因为,与我们目前看到的所有指令不同的是,invokestatic包含了两个额外的字节来构建对于被调用方法的引用(除了操作符)。javap把这个引用显示为#2,它是calc方法的符号引用,被前面提到的常量池所解析。

其它新的信息显然就是calc方法自身的代码。它首先把第一个整型参数加入操作数栈顶(iload_0)。下一条指令i2d通过扩展转换把它转成double类型。double型的结果替换了操作数栈顶的值。

下一条指令把一个double型常量2.0d(从常量池获取)加入操作数栈。然后静态方法Math.pow被调用,到目前为止准备好的两个操作数值是其参数(calc的第一个参数和常量2.0d)。当方法Math.pow返回时,它的结果会存放在调用方的操作数栈中。如下图所示。
在这里插入图片描述
同样的过程适用于对Math.pow(b, 2)的计算:
在这里插入图片描述
下一条指令dadd从栈顶取出两个中间计算结果,进行求和,把结果放回栈顶。最后,invokestatic 在求和结果上调用Math.sqrt,并且使用缩小转换把double转成了int(d2i)。生成的整数返回到main方法中,保存回变量c(istore_3)。

欢迎关注微信公众号,获取更多信息。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44742132/article/details/89519097