1.将局部变量表中的变量压入操作数栈中
- xload_n or xload n 将数据压入栈
- iload_1:将局部变量表中下标为 1 的 int 变量压入操作数栈中。
- aload_2:将局部变量表中下标为 2 的引用数据类型变量(此时为 String)压入操作数栈中。
- lload_3:将局部变量表中下标为 3 的 long 型变量压入操作数栈中。
- iload 5:将局部变量表中下标为 5 的 int 变量(实际为 boolean)压入操作数栈中。
2.将常量池中的常量压入操作数栈中
根据数据类型和入栈内容的不同,此类又可以细分为 const 系列、push 系列和 Idc 指令。
3.将栈顶的数据出栈并装入局部变量表中
- xstore_(x 为 i、l、f、d、a,n 默认为 0 到 3)
- xstore(x 为 i、l、f、d、a)
4.算术指令
- 加法指令:iadd、ladd、fadd、dadd
- 减法指令:isub、lsub、fsub、dsub
- 乘法指令:imul、lmul、fmul、dmul
- 除法指令:idiv、ldiv、fdiv、ddiv
- 求余指令:irem、lrem、frem、drem
- 自增指令:iinc
5.对象的创建和访问指令
5.1创建指令
数组也是一种对象,但它创建的字节码指令和普通的对象不同。创建数组的指令有三种:
- newarray:创建基本数据类型的数组
- anewarray:创建引用类型的数组
- multianewarray:创建多维数组
普通对象的创建指令只有一个,就是 new,它会接收一个操作数,指向常量池中的一个索引,表示要创建的类型。
5.2字段访问指令
字段可以分为两类,一类是成员变量,一类是静态变量(static 关键字修饰的),所以字段访问指令可以分为两类:
- 访问静态变量:getstatic、putstatic。
- 访问成员变量:getfield、putfield,需要创建对象后才能访问。
6.方法调用和返回指令
方法调用指令有 5 个,分别用于不同的场景:
- invokevirtual:用于调用对象的成员方法,根据对象的实际类型进行分派,支持多态。
- invokeinterface:用于调用接口方法,会在运行时搜索由特定对象实现的接口方法进行调用。
- invokespecial:用于调用一些需要特殊处理的方法,包括构造方法、私有方法和父类方法。
- invokestatic:用于调用静态方法。
- invokedynamic:用于在运行时动态解析出调用点限定符所引用的方法,并执行。
7.操作数栈管理指令
常见的操作数栈管理指令有 pop、dup 和 swap。
- 将一个或两个元素从栈顶弹出,并且直接废弃,比如 pop,pop2;
- 复制栈顶的一个或两个数值并将其重新压入栈顶,比如 dup,dup2,dup_×1,dup2_×1,dup_×2,dup2_×2;
- 将栈最顶端的两个槽中的数值交换位置,比如 swap。
这些指令不需要指明数据类型,因为是按照位置压入和弹出的。