目录
2.3.2java.lang.invoke(MethodHandle方法的引用)
1运行时栈帧结构
1.1局部变量表
1.1.1功能
1.1.2 slot
- 32位
- reference类型
- 64位
long和double
1.1.3 this
1.2操作数栈
1.3动态连接
1.4方法返回地址(方法出口)
方法退出的两个方式:
正常完成出口:遇到方法返回的字节码指令
异常完成出口:方法执行过程中遇到异常,且未在方法内部处理
2方法调用
2.1解析
类加载的解析阶段,会将一部分符号引用转化为直接引用,这种转化成功的前提是:
方法在运行之前就有一个可确定的调用版本,且这个调用版本在运行期不可变。这类方法调用称为解析。
- 5个方法调用字节码指令
- 虚方法与非虚方法
final方法是非虚方法,虽然final方法由invokevirtual调用
2.2分派(静态或动态)
2.2.1静态分派(例如:重载)
静态分派:依据静态类型来定位方法执行版本
举例:编译器在重载时通过参数的静态类型选择方法执行版本
代码示例片段:
2.2.2动态分派(重写)
实现原理:invokevirtual指令的多态查找过程
重写的方法选择实际类型作为方法执行版本(动态分派)
2.2.3单分派与多分派
方法的宗量:方法的接收者(实际执行者)与方法的参数
- 静态多分派
- 动态单分派
2.2.4个人理解
在多态中,有一句经典的口诀:编译时看左边,运行时看右边。编译看左边是因为静态分派发生在编译阶段,运行看右边是因为运行时是动态分派。
私货:
Java是静态多分派,动态单分派。所以在动态分派的时候invokevirtual指令需要按继承关系从下往上搜寻方法。我在想,如果是动态多分派,应该就不用搜寻,而是直接定位了,不知道想的对不对。
2.2.5虚拟机动态分派的实现
动态分派需要运行时在类的方法元数据中寻找方法,而动态分派非常频繁,所以虚拟机采用优化手段解决,包括稳定优化和激进优化。
稳定优化:虚方法表
2.3动态类型语言支持(JDK1.7)
2.3.1动态类型语言
类型检查主体过程在运行期而非编译期
2.3.2java.lang.invoke(MethodHandle方法的引用)
Java语言不能单独把一个函数作为参数进行传递。
2.3.3invokedynamic指令
看不懂以后补充
3基于栈的字节码执行引擎
3.1解释执行
C/C++编译器走下方路径,词法分析、语法分析、优化器及目标代码生成器独立于执行引擎,形成完整的编译器。
Javac编译器完成了字节码指令流之前的过程,解释器在虚拟机内部。
3.2基于栈的指令集和基于寄存器的指令集
- 基于栈
指令流中的指令大部分都是零地址指令,依赖操作数栈进行工作
优点:可移植
缺点:速度慢(栈实现在内存中,频繁内存访问。以及出入栈操作产生更多指令)
- 基于寄存器
3.3基于栈的解释器执行过程