JVM指令
IINC var incr 将局部变量表中的第var个变量增加incr,并把新值存到局部变量表
本地变量操作表对应的下标是从0开始的,比如下面一段程序
public void print(int age) {
int a = age;
a++;
}
对应的字节码文件
stack=1, locals=3, args_size=2//这里的参数为什么是2,因为参数里面有个this,这个this是隐藏的,在JVM中是以参数的形式传递进去的
iload_1//将局部变量表中的第1个槽,也就是age这个值,0是this,压入操作数栈栈顶
istore_2//将操作数栈顶的值,这里就是age,存到局部变量表的第二个槽,也就是a
iinc 2, 1//将局部变量表中的第二个槽的a加1
return//方法返回
注意,如果局部变量中有long或者double类型的值,那么会占用局部变量两个槽,如有局部变量int age,long l, double d, short s, byte b,那么对应的槽应该是1,2,4,6,7
byte,short,char,int,boolean类型的操作指令统一使用ILOAD或者ISTORE这些指令
二、栈操作指令
指令 栈操作前 栈操作后
举个例子
public void print(int age, String name) {
this.age = age;
this.name = name;
}
对应的字节码指令
aload_0 //将this入栈
dup //复制一个this
aload_1 //将age入栈
putfield #n //给age复制,这里的n表示一个数字,#n表示索引,对应常量池中的常量
aload_2 //将name入栈
putfield #n //给name复制
三、常量操作
如:public void print(){
int a1 = 1; //ICONST_1将1入栈
//ISTORE_1 将1存入局部变量表1中,即a1
int a2 = 10; //BIPUSH 10
//ISTORE 2
int a3 = 100; // SIPUSH 100
//ISTORE 3
float a4 = 123f; //LDC #4这个#4是引用了常量池里的值,123
//FLOAD 4
}
四、算术和逻辑操作指令
五、转换
六、对象,字段,方法操作
七、数组操作
八、跳转语句
九、return
十、泛型
如:public class Test<T> ==> <T:Ljava/lang/Object;>
public class Test<T> extends ArrayList<E> ==> <T:Ljava/lang/Object;>Ljava/util/ArrayList<TE;>;
static <T> Class<? extends T> m (int n) ==> <T:Ljava/lang/Object;>(I)Ljava/lang/Class<+TT;>;
List<E> ==> Ljava/util/List<TE;>;
List<?> ==> Ljava/util/List<*>;
List<? extends Number> ==> Ljava/util/List<+Ljava/lang/Number;>;
List<? super Integer> ==> Ljava/util/List<-Ljava/lang/Integer;>;
List<List<String>[]> ==> Ljava/util/List<[Ljava/util/List<Ljava/lang/String;>;>;
HashMap<K, V>.HashIterator<K> ==> Ljava/util/HashMap<TK;TV;>.HashIterator<TK;>;
注意:如果是定义定义泛型,比如class Test<T>,方法中的<T>这类T,在写泛型签名的时候应当写成T:Ljava/lang/Object;而不是TT;在其他非定义泛型的位置,写成TT;
十一、描述符表
十二、方法描述符