方法调用指的是确定被调用方法的版本。

java虚拟机中的方法调用指令如下:

invokestatic:调用静态方法

invokespecial:调用实例构造器<init>() 方法,私有方法和父类方法

invokevirtual:调用所有的虚方法

invokeinterface:调用接口方法,运行期会确定一个实现该接口的对象

invokedynamic:会在运行时动态解析出调用限定符所引用的方法,然后再执行该方法。该指令是jdk7新增的。

invokestatic和invokespecal调用的方法都称为非虚方法,在类加载阶段就能明确调用方法的版本。注:有一个特殊的,被final修饰否方法,虽然是由invokevirtual调用的,但是该方法也只有一个版本,所以符合非虚方法,且java语言规范里明确规定final方法是非虚方法。

方法调用分为解析调用和分派调用。

分派调用又根据宗量分为单分派和多分派。

宗量:方法的接收者和参数称为宗量。

解析调用就是在编译阶段就会确认方法版本,在类加载时会把涉及到的符合引用转换为直接引用,不必等到运行期去完成。

分派(dispatch)调用可能是静态的,也可能是动态的,分为静态单分派,静态多分派,动态单分派,动态多分派四种。

静态分派---重载

静态分派属于多分派类型,根据2个宗量选择:静态类型是父类还是子类,方法参数

动态分派---重写

动态分派对应的invokevirtual指令。java的动态分派属于单分派,因为只需要关心该方法的接受者的实际类型。方法参数的类型在编译器已经确定了。

动态分派在java虚拟机中的实现过程:

动态分派的动作执行是非常频繁的,因此虚拟机一般不会频繁地去反复搜索类型元数据。而是将类型在方法区中建立一个虚方法表vtable,对应的,invokeinterface也会建立一个虚接口表itable

虚拟机利用虚方法表来代替元数据查找以提高性能.虚方法表中存放了各个方法的实际入口地址。