JVM04 Java虚拟机是如何执行方法调用的?

要调用就要先识别,Java和Java虚拟机是如何识别目标方法的呢?
在 Java 中,方法存在重载以及重写的概念,重载指的是方法名相同而参数类型不相同的方法之间的关系,重写指的是方法名相同并且参数类型也相同的方法之间的关系。
在Java 虚拟机中,除了方法名和参数类型之外,它还会考虑返回类型。

在 Java 虚拟机中,识别又分两种情况,静态绑定和动态绑定
静态绑定指的是在解析时便能够直接识别目标方法的情况,而动态绑定则指的是需要在运行过程中根据调用者的动态类型来识别目标方法的情况。由于 Java 编译器已经区分了重载的方法,因此可以认为 Java 虚拟机中不存在重载。

JVM提供了如下方法调用指令:
1、invokestatic: 调用静态方法。
2、invokespecial: 调用私有实例方法、构造器,以及使用super关键字调用父类的实例方法或构造器,和所有实现接口的默认方法。
3、invokevirtual: 调用虚方法即非私有的实例方法。
4、invokeinterface: 调用接口方法,在运行时再确定一个实现此接口的对象。
5、invokedynamic: 调用动态方法,在运行时动态解析出调用点限定符所引用的方法之后,调用该方法。

在 class 文件中,Java 编译器会用符号引用指代目标方法。在执行调用指令前,它所附带的符号引用需要被解析成实际引用。对于可以静态绑定的方法调用而言,实际引用为目标方法的指针。对于需要动态绑定的方法调用而言,实际引用为辅助动态绑定的信息。

虚方法调用包括invokevirtual指令和 invokeinterface指令。如果这两种指令所声明的目标方法被标记为 final,那么 Java 虚拟机会采用静态绑定。否则,Java 虚拟机将采用动态绑定,在运行过程中根据调用者的动态类型,来决定具体的目标方法。

Java 虚拟机的动态绑定是通过方法表这一数据结构来实现的。方法表中每一个重写方法的索引值,与父类方法表中被重写的方法的索引值一致。在解析虚方法调用时,Java 虚拟机会纪录下所声明的目标方法的索引值,并且在运行过程中根据这个索引值查找具体的目标方法。

Java 虚拟机中的即时编译器会使用内联缓存来加速动态绑定。Java 虚拟机所采用的单态内联缓存将纪录调用者的动态类型,以及它所对应的目标方法。

当碰到新的调用者时,如果其动态类型与缓存中的类型匹配,则直接调用缓存的目标方法。否则,Java 虚拟机将该内联缓存劣化为超多态内联缓存,在今后的执行过程中直接使用方法表进行动态绑定。

你可能感兴趣的:(JVM04 Java虚拟机是如何执行方法调用的?)