【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.方法内联

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

相关推荐
花归去4 分钟前
echarts 柱状图包含右侧进度
开发语言·前端·javascript
wjs20245 分钟前
Java 数组
开发语言
码农水水6 分钟前
大疆Java面试被问:TCC事务的悬挂、空回滚问题解决方案
java·开发语言·人工智能·面试·职场和发展·单元测试·php
qq_25183645711 分钟前
基于java Web 个人网站系统设计与实现
java·开发语言·数据库
Eternity∞23 分钟前
基于Linux系统vim编译器情况下的C语言学习
linux·c语言·开发语言·学习·vim
周末吃鱼23 分钟前
Lambda作用域
java·开发语言
故事不长丨40 分钟前
C#进制转换:从基础原理到实战应用
开发语言·c#·进制转换·16进制·2进制·10进制
无言(* ̄(エ) ̄)42 分钟前
进程---Linux/C语言
java·开发语言·算法
浪客川1 小时前
【百例RUST - 005】所有权和切片
开发语言·后端·rust
古城小栈1 小时前
Axum: Rust 好用的 Web 框架
开发语言·rust