【04】JVM是如何执行方法调用的

一、重载与重写

1.重载

Java编译器会根据所传入参数的生命类型选取重载方法,选取的过程分为三个阶段
Created with Raphaël 2.3.0 开始 不考虑基本类型自动装拆箱以及可变长参数的情况下选取重载方法 Y or N 结束 允许基本类型自动装拆箱以及不允许可变长参数的情况下选取重载方法 Y or N 结束 允许基本类型自动装拆箱以及允许可变长参数的情况下选取重载方法 结束 yes no yes no

若Java编译器在同一个阶段找到多个适配的方法,则会其中选择一个最为贴切的,决定贴切程度的关键就是形式参数类型的继承关系。编译器会认为子类更为贴切。

举个例子说明下上面这句话

java 复制代码
void invoke(Object obj, Object... args) { ... }
void invoke(String s, Object obj, Object... args) { ... }

invoke(null, 1);    // 调用第二个 invoke 方法,因为String是Object的子类
invoke(null, 1, 2); // 调用第二个 invoke 方法,因为String是Object的子类
invoke(null, new Object[]{1}); // 只有手动绕开可变长参数的语法糖,
                               // 才能调用第一个 invoke 方法

2.重写

如果子类定义了与父类中非私有方法同名的方法,且这两个方法的参数类型相同就是重写

二、JVM的静态绑定和动态绑定

Java虚拟机中的静态绑定指的是在解析时能够直接识别目标方法的情况,动态绑定指的是在运行过程中根据调用者的动态类型来识别目标方法的情况

Java字节码中与调用相关的指令共有五种:

1.invokestatic:用于调用静态方法

2.invokespecial:用于调用私有实例方法、构造器以及使用super关键字调用父类的实例方法或构造器,和所实现接口的默认方法

3.invokevirtual:用于调用非私有实例方法

4.invokeinterface:用于调用接口方法

5.invokedynamic:用于调用动态方法

Java虚拟机中采取了用空间换取时间的策略来实现动态绑定,为每个类生成一张方法表,用以快速定位目标方法。

1.方法表

方法表本质上是一个数组,每个数组元素指向一个当前类及其祖先类中的非私有的实例方法。方法表中有两个特点:1.子类方法表中包含父类方法表中的所有方法 2.子类方法在方法表中的索引值,与它所重写的父类方法的索引值相同

方法调用指令中的符号引用会在执行之前解析成实际引用。对于静态绑定的方法调用而言,实际引用指向具体的目标方法;对于动态绑定的方法调用而言,实际引用是方法表的索引值。

2.内联缓存

虚函数是有一定性能消耗的,有多种手段用来优化虚函数,比如即时编译的两种优化手段:1.内联缓存 2.方法内联

内联缓存,缓存虚方法调用中调用者的动态类型,以及该类型所对应的目标方法。在之后的执行过程中,若碰到已缓存的类型,会直接调用该类型对应的目标方法;没有碰到已缓存的类型,则会退化至使用基于方法表的动态绑定。

相关推荐
诗书画唱3 小时前
【前端教程】JavaScript 实现图片鼠标悬停切换效果与==和=的区别
开发语言·前端·javascript
一枝小雨3 小时前
【C++】Vector完全指南:动态数组高效使用
开发语言·c++·笔记·vector·学习笔记·std库
诗书画唱3 小时前
【前端教程】JavaScript DOM 操作实战案例详解
开发语言·前端·javascript
jiaway3 小时前
【C语言】第一课 环境配置
c语言·开发语言
小红帽2.04 小时前
从零构建一款开源在线客服系统:我的Go语言实战之旅
开发语言·golang·开源
slim~4 小时前
Java基础第9天总结(可变参数、Collections、斗地主)
java·开发语言
ComputerInBook5 小时前
C++编程语言:标准库:第37章——正则表达式(Bjarne Stroustrup)
开发语言·c++·正则表达式
A尘埃5 小时前
智能工单路由系统(Java)
java·开发语言·智能工单
Source.Liu5 小时前
【Python基础】 13 Rust 与 Python 注释对比笔记
开发语言·笔记·python·rust
qq_195551695 小时前
代码随想录70期day3
开发语言·python