之前的文章就简单的给大家介绍了各种锁的介绍与使用(文末有对应的链接),目前这章为之后讲解锁的操作底层实现先奠定下基础。
JAVA基本类型转换
JAVA
中基本类型的转换是不涉及操作数的,转换的值是直接从栈顶端获得,JAVA
虚拟机从栈顶弹出一个值,对他进行转换,然后再把转换结果压入栈中。
1.int、long、float、double 类型之间的相互转换
操作码 | 操作数 | 备注 |
i2l | 无 | 将int类型的值转换为long类类型 |
i2f | 无 | 将int类型的值转换为float类类型 |
i2d | 无 | 将int类型的值转换为double类类型 |
l2i | 无 | 将long类型的值转换为int类类型 |
l2f | 无 | 将long类型的值转换为float类类型 |
l2d | 无 | 将long类型的值转换为double类类型 |
f2i | 无 | 将float类型的值转换为int类类型 |
f2l | 无 | 将float类型的值转换为long类类型 |
f2d | 无 | 将float类型的值转换为double类类型 |
d2i | 无 | 将double类型的值转换为int类类型 |
d2l | 无 | 将double类型的值转换为long类类型 |
d2f | 无 | 将double类型的值转换为float类类型 |
2.int数据类型向byte、char、short类型的转换
操作码 | 操作数 | 备注 |
i2b | 无 | 将int类型的值转换为byte类型值,进行带符号扩展,恢复为int类型压入栈 |
i2c | 无 | 将int类型的值转换为char类型值,进行零扩展,恢复成int类型压入栈 |
i2s | 无 | 将int类型的值转换为short类型值,进行带符号扩展,恢复成int类型压入栈 |
不存在比int
类型占据更小空间的数据类型转化为int
类型操作码。因为上面三种才进行压入栈的时候,就已经转换为int
类型,然后再对int
类型值进行运算,最后得到int
类型值。
Demo:
public static void main(String[] args) { byte a =2; byte b =1; byte c = (byte) (a+b); }复制代码
public static void main(java.lang.String[]); Code: 0: iconst_2 //常量2入栈 1: istore_1 //弹出栈顶元素存入位置1的局部变量 2: iconst_1 3: istore_2 4: iload_1 //取出位置1的局部变量值入栈 5: iload_2 6: iadd //加法运算 7: i2b //int类型转化为byte类型值 8: istore_3 //弹出栈顶元素存入位置3的局部变量 9: return}复制代码
JAVA常量操作
1.常量值隐含包含在操作码内部
操作码 | 操作数 | 备注 |
iconst_m1 | 无 | 将int类型值-1压入栈 |
iconst_0 | 无 | 将int类型值0压入栈 |
iconst_1 | 无 | 将int类型值1压入栈 |
iconst_2 | 无 | 将int类型值2压入栈 |
iconst_3 | 无 | 将int类型值3压入栈 |
fconst_0 | 无 | 将float类型值0压入栈 |
fconst_1 | 无 | 将float类型值1压入栈 |
fconst_2 | 无 | 将float类型值2压入栈 |
lconst_0 | 无 | 将long类型值0压入栈 |
lconst_1 | 无 | 将long类型值1压入栈 |
dconst_0 | 无 | 将double类型值0压入栈 |
dconst_1 | 无 | 将double类型值1压入栈 |
aconst_null | 无 | 将空(null)对象压入栈 |
2.常量值在字节码中跟随操作码之后
操作码 | 操作数 | 备注 |
bipush | 一个byte类型的数 | 将byte类型的数转换为int类型的数,然后压入栈 |
sipush | 一个short类型的数 | 将short类型的数转换为int类型的数,然后压入栈 |
3.从常量池中取出常量
操作码 | 操作数 | 备注 |
ldc | 无符号8位数indexbyte | 从由indexbyte指向的常量池入口中取出一个字长的值,然后将其压入栈 |
ldc_w | 无符号16位数indexshort | 从由indexbyte指向的常量池入口中取出两个字长的值,然后将其压入栈 |
JAVA通用栈以及局部变量的操作
1.通用栈操作
操作码 | 操作数 | 备注 | Demo |
nop | 无 | 不做任何操作 | 前:...,word后:...,word,word |
pop | 无 | 从操作数栈弹出栈顶部一个字 | 前:...,word后:... |
pop2 | 无 | 从栈顶数弹出最顶端的两个字 | |
swap | 无 | 交换栈顶部的两个字 | 前:...,word2,word1后:...,word1,word2 |
dup | 无 | 复制栈顶部的一个字 | |
dup2 | 无 | 复制栈顶部的两个字 | |
dup2 | 无 | 复制栈顶部的两个字 | |
dup_x1 | 无 | 复制栈顶部的一个字,将复制内容以及原来弹出的两个字长的内容压入栈 | 前:...,word2,word1后:...,word1,word2,word1 |
dup_x2 | 无 | 复制栈顶部的一个字,将复制内容以及原来弹出的三个字长的内容压入栈 | 前:.,word3,word2,word1后:.,word1,word3,word2,word1 |
dup2_x1 | 无 | 复制栈顶部的两个字,将复制内容以及原来弹出的三个字长的内容压入栈 | |
dup2_x2 | 无 | 复制栈顶部的两个字,将复制内容以及原来弹出的四个字长的内容压入栈 | |
2.局部变量压入栈
1.将一个字长的局部变量压入栈
操作码 | 操作数 | 备注 |
iload | vindex | 将位置为vindex的int类型的局部变量压入栈 |
iload_0 | 无 | 将位置为0的int类型的局部变量压入栈 |
iload_1 | 无 | 将位置为1的int类型的局部变量压入栈 |
iload_2 | 无 | 将位置为2的int类型的局部变量压入栈 |
iload_3 | 无 | 将位置为3的int类型的局部变量压入栈 |
fload | vindex | 将位置为vindex的float类型的局部变量压入栈 |
fload_0 | 无 | 将位置为0的float类型的局部变量压入栈 |
fload_1 | 无 | 将位置为1的float类型的局部变量压入栈 |
fload_2 | 无 | 将位置为2的float类型的局部变量压入栈 |
fload_3 | 无 | 将位置为3的float类型的局部变量压入栈 |
2.将两个字长的局部变量压入栈
操作码 | 操作数 | 备注 |
lload | vindex | 将位置为vindex和(vindex+1)的long类型的局部变量压入栈 |
lload_0 | 无 | 将位置为0和1的long类型的局部变量压入栈 |
lload_1 | 无 | 将位置为1和2的long类型的局部变量压入栈 |
lload_2 | 无 | 将位置为2和3的long类型的局部变量压入栈 |
lload_3 | 无 | 将位置为3和4的long类型的局部变量压入栈 |
dload | vindex | 将位置为vindex和(vindex+1)的double类型的局部变量压入栈 |
dload_0 | 无 | 将位置为0和1的double类型的局部变量压入栈 |
dload_1 | 无 | 将位置为1和2的double类型的局部变量压入栈 |
dload_2 | 无 | 将位置为2和3的double类型的局部变量压入栈 |
dload_3 | 无 | 将位置为3和4的double类型的局部变量压入栈 |
3.将对象引用局部变量压入栈
操作码 | 操作数 | 备注 |
aload | vindex | 将位置为vindex的对象引用局部变量压入栈 |
aload_0 | 无 | 将位置为0的对象引用局部变量压入栈 |
aload_1 | 无 | 将位置为1的对象引用局部变量压入栈 |
aload_2 | 无 | 将位置为2的对象引用局部变量压入栈 |
aload_3 | 无 | 将位置为3的对象引用局部变量压入栈 |
4.弹出栈顶元素,赋值局部变量
移动一个字长的操作:
操作码 | 操作数 | 备注 |
istore | vindex | 从栈中弹出int类型值,然后存到位置为vindex的局部变量中 |
istore_0 | 无 | 从栈中弹出int类型值,然后存到位置为0的局部变量中 |
istore_1 | 无 | 从栈中弹出int类型值,然后存到位置为1的局部变量中 |
istore_2 | 无 | 从栈中弹出int类型值,然后存到位置为2的局部变量中 |
istore_3 | 无 | 从栈中弹出int类型值,然后存到位置为3的局部变量中 |
fstore | vindex | 从栈中弹出float类型值,然后存到位置为vindex的局部变量中 |
fstore_0 | 无 | 从栈中弹出float类型值,然后存到位置为0的局部变量中 |
fstore_1 | 无 | 从栈中弹出float类型值,然后存到位置为1的局部变量中 |
fstore_2 | 无 | 从栈中弹出float类型值,然后存到位置为2的局部变量中 |
fstore_3 | 无 | 从栈中弹出float类型值,然后存到位置为3的局部变量中 |
移动两个字长的操作:
操作码 | 操作数 | 备注 |
lstore | vindex | 从栈中弹出long类型值,然后存到位置为vindex和(vindex+1)的局部变量中 |
lstore_0 | 无 | 从栈中弹出long类型值,然后存到位置为0和1的局部变量中 |
lstore_1 | 无 | 从栈中弹出long类型值,然后存到位置为1和2的局部变量中 |
lstore_2 | 无 | 从栈中弹出long类型值,然后存到位置为2和3的局部变量中 |
lstore_3 | 无 | 从栈中弹出long类型值,然后存到位置为3和4的局部变量中 |
dstore | vindex | 从栈中弹出double类型值,然后存到位置为vindex和(vindex+1)的局部变量中 |
dstore_0 | 无 | 从栈中弹出double类型值,然后存到位置为0和1的局部变量中 |
dstore_1 | 无 | 从栈中弹出double类型值,然后存到位置为1和2的局部变量中 |
dstore_2 | 无 | 从栈中弹出double类型值,然后存到位置为2和3的局部变量中 |
dstore_3 | 无 | 从栈中弹出double类型值,然后存到位置为3和4的局部变量中 |
移动引用的操作: 移动两个字长的操作:
操作码 | 操作数 | 备注 |
astore | vindex | 从栈中弹出对象引用,然后存到位置为vindex的局部变量中 |
astore_0 | 无 | 从栈中弹出对象引用,然后存到位置为0的局部变量中 |
astore_1 | 无 | 从栈中弹出对象引用,然后存到位置为1的局部变量中 |
astore_2 | 无 | 从栈中弹出对象引用,然后存到位置为2的局部变量中 |
astore_3 | 无 | 从栈中弹出对象引用,然后存到位置为3的局部变量中 |
5.wide指令
无符号8位局部变量索引,把方法中局部变量数的限制在256以下。一条单独的wide指令可以将8位的索引再扩展8位。跳转指令并不允许直接跳转到被wide指令修改过的操作码。
操作码 | 操作数 | 备注 |
wide | iload,index | 从局部变量位置为index的地方取出int类型值,并将其压入栈 |
wide | lload,index | 从局部变量位置为index的地方取出long类型值,并将其压入栈 |
wide | fload,index | 从局部变量位置为index的地方取出float类型值,并将其压入栈 |
wide | dload,index | 从局部变量位置为index的地方取出double类型值,并将其压入栈 |
wide | aload,index | 从局部变量位置为index的地方取出对象引用,并将其压入栈 |
wide | istore,index | 从栈中弹出int类型值,将其存入位置为index的局部变量中 |
wide | lstore,index | 从栈中弹出long类型值,将其存入位置为index的局部变量中 |
wide | lstore,index | 从栈中弹出long类型值,将其存入位置为index的局部变量中 |
wide | fstore,index | 从栈中弹出float类型值,将其存入位置为index的局部变量中 |
wide | dstore,index | 从栈中弹出double类型值,将其存入位置为index的局部变量中 |
wide | astore,index | 从栈中弹出对象引用,将其存入位置为index的局部变量中 |
以上先介绍一部分JAVA
字节码中的一些命令,接下来还有一些方法调用等等指令,下一篇文章给大家介绍下。