jvm --白话 解析调用和 分派调用
重点:解析调用和分派调用不是互斥的,只是从不同维度进行说明类的调用
方法调用
方法调用不同于方法的执行,它不涉及代码内容,方法调用阶段的唯一任务就是缺点被调用方法的版本(父类,子类,重载等等),Class文件的编译过程中不包括传统编译器的连接步骤,一切方法调用都在class文件里面存储的符号引用,但它不是实际运行内存布局的入口地址。
jvm提供了五条方法调用字节码指令:
1.invokestatic:调用静态方法。
2.invokespecial:调用实例构造器<init>方法,私有方法和父类方法(super())
3.invokevirtual:调用所有的虚方法( final方法都是非虚方法)
4.invokeinterface:调用接口方法。会在运行期间再确定一个实现次接口的对象。
5.invokedynamic:运行时期动态解析出调用点限定符所引用的方法,然后再执行该方法,在次之前的4条指令,分派逻辑都是固化在jvm里面的,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的
非虚方法:
invokestatic , invokespecial 和 final修饰的 invokevirtual
虚方法:
除了非虚方法的方法。
解析调用 :一定是一个静态的过程,在编译期间就可以完全确定,在类装载的解析阶段就会把涉及的符号引用全部转换为可确定的直接引用,不会延迟到运行时去完成。
而 符合 “编译期可知,运行期不变的”这个要求的方法,就是静态方法,接口方法和 final方法 。而jvm可没有这些概念,只有 上面的五条字节码指令,所以,invokestatic,invokespecial和final修饰的invokevirtual都 时可以静态 调用的。
解析调用,那就只能时非虚方法
分派调用:可能是静态的,也可能是动态的,它的分类:静态单分派,静态多分派,动态单分派,动态多分派。
静态方法,也存在方法重载(构造器类似)。所以 一样存在 分派调用问题。
分派调用,可以是 虚方法 和 非虚方法
如果有一个静态方法,存在重载,它到底是静态调用还是分派调用呢?
都是。还是回到到文章第一行,解析调用和分派调用不是互斥的,只是从不同维度进行说明类的调用
public class CallTest { public static void main(String[] args) { Human human = new Man(); m(human); } private static void m(Human human){ System.out.println("human"); } private static void m(Man man){ System.out.println("man"); } private static void m(Woman woman){ System.out.println("woman"); } } class Human{} class Man extends Human{} class Woman extends Human{}
human
运行结果应该是没有争议的。这个地方是解析调用,也是 分派调用
main方法的方法字节码为
对应的4号常量
在解析阶段,就可以直接确定,不存在方法的重写,直接是 解析调用。存在 多个重载方法,存在根据静态类型判断调用那个方法的问题,是 静态分派。
posted on 2021-04-05 20:11 xingshouzhan 阅读(111) 评论(0) 编辑 收藏 举报