以下是在学习了《深入理解JVM》之后的对知识点的总结,其中对方法调用那一章做了大量实践和分析。
文章目录
解释型还是编译型
- 字节码的执行有解释型和编译型,根据具体情况才能说明java到底是什么执行方式。
基于栈还是基于寄存器
- 虚拟机是基于栈的指令集,栈指的是java虚拟机栈,指令集指的字节码指令。
字节码指令在哪儿
- 执行的字节码指令存放在字节码文件里的方法表里的code属性中。
java虚拟机栈与栈帧的关系
- 虚拟机栈的基本单位为栈帧,栈帧之间的排列是先进后出。每个栈帧包括了局部变量表,操作数栈,动态连接,方法返回地址以及其他一些信息。
- 每个栈帧的大小在编译期已经决定,因此栈帧中的每个结构都在编译期确定。
- 虚拟机栈是线程私有,线程结束栈帧的所有内存都会清除。
局部变量表
-
局部变量表的单位为slot。
-
一个slot的大小必须要装的下除long,double类型之外其他基本类型,一般4个字节,也就是32位。
-
对于long,double类型使用两个slot存放。
-
局部变量表利用索引来获取值,就如同数组一样。局部变量表存放了方法的参数,以及方法中定义的所有变量。
-
如果是实例方法,局部变量表第0个索引为this指针,其它变量从1开始索引。如果是类方法,没有this指针,其它变量直接从0开始索引。
-
局部变量表的大小在编译期就已经决定,并存放于字节码文件中的方法表的max_locals字段中。
操作数栈
- 操作数栈是一种先进后出的栈结构,是字节码执行过程中数据交互的场所。
动态连接
- 动态连接指向常量池中的一个方法符号引用。
- 与方法的动态连接有关。
方法返回地址
- 一个方法没有出现异常,或者异常被捕捉为正常退出,有返回值。否则,为不正常退出,没有返回值。不管正不正常都会返回上一次调用地址。
栈帧与方法的关系
- 当一个方法执行之后,会在线程所对应的虚拟机栈空间分配一个栈帧,一个栈帧代表一个方法。
- 方法完成后,栈帧出栈。
字节码指令中的四个方法调用指令
- invokestatic,invokestatic指令调用的方法表示在类加载过程之后,通过解析过程就已经确定。这些方法包括静态方法,实例构造器,私有方法和类方法四种。
- 解析过程就是将符号引用替换为直接引用。
- invokevirtual为虚方法指令。
- invokeinterface为接口方法指令。
invokevirtual指令解析过程
- 针对的是所调用方法的对象,而非方法的参数。
- 具体过程如下:
- 找到操作数栈栈顶所指对象的实际类型。
- 如果此类型重写了方法,那么进行校验并执行,否则抛出异常
- 如果没有重写,继续寻找父类或接口。
- 始终没有找到抛出异常。
静态分派,重载,编译期确定
- 重载是多态的体现,但是重载并不是在程序运行过程中动态绑定,虽然调用重载方法使用了invokevirtual,但是invokevitual的功能对重载并没有影响。
- 重载在编译期通过参数的静态类型来决定调用那个方法。
- 重载是的选择并不是唯一的,而是最适合的。
动态分派,重写,运行时确定
- 动态分派是多态的体现,与重载不同,并不能在编译期确定。
- 在字节码指令里,调用重写的方法,根据invokevitual的解析流程,会判断调用对象的实际类型,通过实际类型来选择调用哪个方法。
来源:CSDN
作者:八千里路云和月laiker
链接:https://blog.csdn.net/qq_37744360/article/details/104615503