很多Java工程师语法用的很,但是真的让他说说Java是怎样运行的,我相信他会懵逼!!!
希望处于这个阶段的同学可以仔细阅Class文件系列的文章,这里涵盖了Class文件的绝大部分内容,当你阅读并理解之后,相信你不再迷茫。
不知道是否还记得Code属性,不记得的小伙伴建议回顾一下,Code属性中存储了今天我们将要讲解的字节码指令。
今天介绍一下字节码指令(加载和存储指令)。所谓的字节码指令就是JVM在运行时所需要进行的操作,字节码指令大致分以下集中类型:
- 加载和存储指令
- 运算指令
- 类型转换指令
- 对象创建与访问指令
- 操作数栈管理指令
- 控制转移指令
- 方法调用和返回指令
- 异常处理指令
- 同步指令
对于大部分字节码指令,都包含了其操作所对应的数据类型,i对应Integer类型,l代表Long类型,f代表Float类型,d代表Double类型,a代表Reference类型,b代表byte类型,s代表short类型,c代表char类型。
加载和存储指令
加载和存储指令用于将数据在栈帧的局部变量表和操作数栈中传输。
局部变量加载到操作数栈
iload,iload_<n>,lload, lload_<n>, fload, fload_<n>, dload, dload_<n>, aload, aload_<n>
<n>其实只是助记符,比如iload_1意思是将局部变量表slot索引为1的int型元素压入操作数栈顶,iload_1完全等同于iload(1)。
操作数栈加载到局部变量表
istore,istore_<n>、lstore, lstore_<n>, fstore, fstore_<n>, dstore, dstore_<n>, astore, astore_<n>。
istore_1作用就是将操作数栈顶元素保存到局部变量表索引为1的位置处。
将常量压入到操作数栈
bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_m1,iconst_<n>,lconst_<l>,fconst_<f>,dconst_<d>。
这里我们说一下ldc、ldc_w、ldc2_w,我们先看一下Java8虚拟机规范对它的定义,如下图:
图上的意思大致是说将常量池中的一些特定类型的常量推入操作数栈顶,这些类型包括int,float,String, Class,java.lang.invoke.MethodType, java.lang.invoke.MethodHandle。
ldc等同于ldc_w, ldc2_w等同于ldc的特定类型的long和double。
public class ClassTest {
public void test() {
Class<Long> c = Long.class;
String s = "test";
int r = Integer.MAX_VALUE;
float f = Float.MAX_VALUE;
long l = Long.MAX_VALUE;
double d = Double.MAX_VALUE;
}
}
注意看红框中的部分,ldc #2,常量池中的第二项是个Class类型,符合虚拟机规范的描述;在看 ldc #3,常量池中的第三项是个String类型,符合虚拟机规范的描述;ldc2_w #8、ldc2_w #11,在常量池的第8和第11项分别是Long和Double型,符合虚拟机规范。
JVM支持的是栈式指令集,在我们代码运行过程中,需要通过加载和存储指令来完成变量在局部变量表和操作数栈之间的传递。
本期的加载和存储指令就介绍到这,我们下期再见!!!
我是shysh95,希望可以和你专注技术的路上并肩作战,做跟绝大多数人不一样的事情,离平庸更远一点,扫码关注微信公众号,更多精彩文章!!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。