硬核万字长文,深入理解 Java 字节码指令(建议收藏) (5)

由于 ls 变量的引用类型为接口 List,所以 ls.add() 调用的是 invokeinterface 指令,等运行时再确定是不是接口 List 的实现对象 ArrayList 的 add() 方法。

invokevirtual #7 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z

由于 als 变量的引用类型已经确定为 ArrayList,所以 als.add() 方法调用的是 invokevirtual 指令。

3)main() 方法中

invokestatic  #11 // Method print:()V

print() 方法是静态的,所以调用的是 invokestatic 指令。

方法返回指令根据方法的返回值类型进行区分,常见的返回指令见下图。

硬核万字长文,深入理解 Java 字节码指令(建议收藏)

06、操作数栈管理指令

常见的操作数栈管理指令有 pop、dup 和 swap。

将一个或两个元素从栈顶弹出,并且直接废弃,比如 pop,pop2;

复制栈顶的一个或两个数值并将其重新压入栈顶,比如 dup,dup2,dup_×1,dup2_×1,dup_×2,dup2_×2;

将栈最顶端的两个槽中的数值交换位置,比如 swap。

这些指令不需要指明数据类型,因为是按照位置压入和弹出的。

举例来说。

public class Dup {
    int age;
    public int incAndGet() {
        return ++age;
    }
}

通过 jclasslib 看一下 incAndGet() 方法的字节码指令。

硬核万字长文,深入理解 Java 字节码指令(建议收藏)

aload_0:将 this 入栈。

dup:复制栈顶的 this。

getfield #2:将常量池中下标为 2 的常量加载到栈上,同时将一个 this 出栈。

iconst_1:将常量 1 入栈。

iadd:将栈顶的两个值相加后出栈,并将结果放回栈上。

dup_x1:复制栈顶的元素,并将其插入 this 下面。

putfield #2: 将栈顶的两个元素出栈,并将其赋值给字段 age。

ireturn:将栈顶的元素出栈返回。

07、控制转移指令

控制转移指令包括:

比较指令,比较栈顶的两个元素的大小,并将比较结果入栈。

条件跳转指令,通常和比较指令一块使用,在条件跳转指令执行前,一般先用比较指令进行栈顶元素的比较,然后进行条件跳转。

比较条件转指令,类似于比较指令和条件跳转指令的结合体,它将比较和跳转两个步骤合二为一。

多条件分支跳转指令,专为 switch-case 语句设计的。

无条件跳转指令,目前主要是 goto 指令。

1)比较指令

比较指令有:dcmpg,dcmpl、fcmpg、fcmpl、lcmp,指令的第一个字母代表的含义分别是 double、float、long。注意,没有 int 类型。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zggffx.html