jvm方法运行原理

354 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

5)条件判断指令

image-20220401120306483

几点说明:

  • byte,short,char 都会按 int 比较,因为操作数栈都是 4 字节
  • goto 用来进行跳转到指定行号的字节码

(6)循环控制指令

比较 while 和 for 的字节码,发现它们是一模一样的

(7)构造方法

a.()V

编译器会按从上至下的顺序,收集所有 static 静态代码块和静态成员赋值的代码,合并为一个特殊的方 法 ()V : ()V 方法会在类加载的初始化阶段被调用

b.()V

编译器会按从上至下的顺序,收集所有 {} 代码块和成员变量赋值的代码,形成新的构造方法,但原始构 造方法内的代码总是在最后

(8)方法调用

不同方法在调用时,对应的虚拟机指令有所区别

  • 私有、构造、被final修饰的方法,在调用时都使用invokespecial指令

  • 普通成员方法在调用时,使用invokespecial指令。因为编译期间无法确定该方法的内容,只有在运行期 间才能确定

  • 静态方法在调用时使用invokestatic指令

  • new 是创建【对象】,给对象分配堆内存,执行成功会将【对象引用】压入操作数栈

  • dup 是赋值操作数栈栈顶的内容,本例即为【对象引用】,为什么需要两份引用呢,一个是要配 合 invokespecial 调用该对象的构造方法 "":()V (会消耗掉栈顶一个引用),另一个要 配合 astore_1 赋值给局部变量

  • 最终方法(final),私有方法(private),构造方法都是由 invokespecial 指令来调用,属于静 态绑定

  • 普通成员方法是由 invokevirtual 调用,属于动态绑定,即支持多态

  • 成员方法与静态方法调用的另一个区别是,执行方法前是否需要【对象引用】

  • 比较有意思的是 d.test4(); 是通过【对象引用】调用一个静态方法,可以看到在调用 invokestatic 之前执行了 pop 指令,把【对象引用】从操作数栈弹掉了😂

  • 还有一个执行 invokespecial 的情况是通过 super 调用父类方法

(9)多态的原理

当执行 invokevirtual 指令时,

  1. 先通过栈帧中的对象引用找到对象
  2. 分析对象头,找到对象的实际 Class
  3. Class 结构中有 vtable,它在类加载的链接阶段就已经根据方法的重写规则生成好了
  4. 查表得到方法的具体地址
  5. 执行方法的字节码