JVM Class详解之二 Method字节码指令

简介:

JVM Class详解之一中我们介绍了Class文件的结构和如何使用16进制编辑器读懂class文件。
今天我们来继续一起下Class文件中Method方法中经过java编译器编译后的Method字节码指令是什么样子的

JVM有哪些字节码指令

首先我们需要了解JVM有哪些字节码指令

第一类load类型

是将本地变量中的数据推送入栈中 (什么是本地变量我们后面聊)
iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_
iload_0:将第一个int型本地变量推送至栈顶
iload中i表示为int型(l为long,f为float,d为double ,a为引用类型),load表示动作为load,
后面的指令大多都是这种结构,先是声明操作数类型,再说明具体动作。
同理 fload:将本地变量的float型数据推送栈顶

第二类store

load是从本地变量到栈顶,store是从栈顶到本地变量
istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_
istore:将栈顶int型数值存入制定数组的指定索引位置

第三类push,const

除了本地变量到栈顶,还有常量到栈顶
bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_
ldc:将int,float或String型常量从常量池中推送至栈顶
iconst_0:将int型0推送至栈顶

第四类 算数操作

加:iadd,ladd,fadd,dadd  :将栈顶两个数值相加并将将结果压入栈顶
减:is ,ls ,fs ,ds 
乘:imul,lmul,fmul,dmul 
除:idiv,ldiv,fdiv,ddiv 
余数:irem,lrem,frem,drem 
取负:ineg,lneg,fneg,dneg 
移位:ishl,lshr,iushr,lshl,lshr,lushr 
按位或:ior,lor 
按位与:iand,land 
按位异或:ixor,lxor 
类型转换:i2l,i2f,i2d,l2f,l2d,f2d(放宽数值转换) 
i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(缩窄数值转换)
这个很简单的顾名思义哈哈。

第五类 比较操作

lcmp:比较栈顶两个long型数值的大小,并将结果(1,0,-1)压入栈顶
fcmpl:比较栈顶两个float型数值的大小,并将结果(1,0,-1)压入栈顶,当其中一个为NaN,将-1压入栈顶
fcmpg:。。。。。其中一个为NaN,将1压入栈顶
dcmpl
dcmpg

第六类 跳转

ifeq:当栈顶int型数值等于0时跳转
ifne:当栈顶int型数值不等于0时跳转
iflt:当栈顶int型数值小于0时跳转
ifge:大于等于0
ifgt:大于0
ifle:小于等于0
if_icmpeq:比较栈顶两个int大小,等于0跳转
if_icmpne:不等于0跳转
。。。
goto:无条件跳转
goto,goto_w,jsr,jsr_w,ret 
ifnull:为null时跳转
ifnonnull:不为null时跳转
finally关键字的实现使用:jsr,jsr_w,ret

第七类 返回操作

ireturn:从当前方法返回int
lreturn:从当前方法放回long
。。。
return:从当前方法返回void

第八类 Class的相关操作

getstatic:获取指定类的静态域,并将其值压入栈顶
putstatic:为指定的类的静态域赋值
getfield:获取指定类的实例域,并将其值压入栈顶
pufield:为指定类的实例域赋值

invokevirtual:调用实例方法
invokespecial:调用超类构造方法,实例初始化方法没有方法
invokestatic:调用静态方法
invokeinterface:调用接口方法
invokedynamic:调用动态方法

new:创建一个对象
newarray:创建一个指定的原始类型数组
anewarray:创建一个引用型的数组,并将其引用值压入栈顶
arraylength:获取数组的长度并压入栈顶
athrow:将栈顶的异常抛出
checkcast:检查类型转换,检查未通过会抛出ClassCastException
instanceof:检查是否是指定的类的实例,如果是,将1压入栈顶,不是将0压入栈顶

monitorenter:获取对象的锁,用于同步方法或者同步块
monitorexit:释放对象的锁

wide:扩展本地变量的宽度

好至此主要的指令已经介绍完毕,怎么分类仁者见仁啦。

HelloWorld搞起

public class HelloWorldMethod{

public intaddNumber(int a,int b){
if(a<0){
return -1;
}
if( b < 0 ){
return -1;
}
int c = a + b;
returnc;
}
}

这个intAddMethod方法传入两个int,判断是否小于0,如果小于返回-1,都不小于返回相加值

我们通过javap -verbose HelloWorldMethod.class 查看字节码指令
screenshot
screenshot
我们按照指令一条一条看
0:iload_1:将本地变量中第一个int (a)加载到栈顶
为什么是a呢,我们再看LovalVariableTable。每个方法都有LocalVariableTable。是本地变量表。我们可以看到在本地变量表中的第一个int就是a
screenshot
1:ifge:判断栈顶的int是否大于0如果大于将1压入栈顶,如果不大于将0压入栈顶
分支1:如果当前值不大于0将0压入栈顶,
分支2:如果当前值大于0跳转到指令6
4:iconst_m1:将整型-1压入栈顶 
5:ireturn

6:iload_2:将本地变量汇总第二个int(b)压入栈顶
7:ifge:判断栈顶的int是否大于0
分支3:如果当前值不大于0,将栈顶压入0
分支4:如果当前值大于0,将1压入栈顶,并跳转到执行12执行
10:iconst_m1:将int -1压入栈顶
11:ireturn:返回栈顶int值

12:iload_1:将本地变量第一个int压入栈顶(a)
13:iload_2:将本地变量第二个int压入栈顶(b)
14:iadd:将栈顶的两个int相加并将结果压入栈顶 a+b
15:istore_3:将栈顶的int值,存入本地变量表中第三个int,第三个int为c,将结果付给了c
screenshot
16:iload_3:将本地变量中的第三个int压入栈顶,取出c
17:ireturn:将栈顶的第一个int返回

LineNumberTable

Code中 还有另外一个东西
screenshot
这个是什么,这个是LineNumberTable,其中记录了编译出来的字节码指令和源码的对应关系
这个属性不是很重要。另外就是一个源码会对应多条指令的

例如源码中的第5行return -1 ,对应指令为4和5
screenshot

好了至此我们就知道了我们JAVA文件编译后的Method中有什么东西,JVM又是怎样读取字节码指令做相应操作的了。

相关文章
|
4月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
391 55
|
5月前
|
Arthas 监控 Java
Arthas redefine(加载外部的.class文件,redefine到JVM里 )
Arthas redefine(加载外部的.class文件,redefine到JVM里 )
165 15
|
4月前
|
Arthas 存储 Java
JVM深入原理(三+四):JVM组成和JVM字节码文件
目录3. JVM组成3.1. 组成-运行时数据区3.2. 组成-类加载器3.3. 组成-执行引擎3.4. 组成-本地接口4. JVM字节码文件4.1. 字节码文件-组成4.1.1. 组成-基础信息4.1.1.1. 基础信息-魔数4.1.1.2. 基础信息-主副版本号4.1.2. 组成-常量池4.1.3. 组成-方法4.1.3.1. 方法-工作流程4.1.4. 组成-字段4.1.5. 组成-属性4.2. 字节码文件-查看工具4.2.1. javap4.2.2. jclasslib4.2.3. 阿里Arthas
80 0
|
4月前
|
存储 安全 Java
JVM深入原理(五):JVM组成和JVM字节码文件
类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析。
55 0
|
11月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
187 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
11月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
133 3
|
11月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
196 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
5月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
342 6
|
8月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
872 166
|
10月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
1632 1