面试系列之-多态JVM的实现原理(JAVA基础)

2023-08-21 20:11:04 浏览数 (1)

多态的机制及分类

一个对象变量可以指示多种实际类型的现象称为多态;允许不同类的对象对同一消息做出响应。方法的重载、类的覆盖(继承和实现)正体现了多态;

重载(overload 发生在一个类中,方法名必须相同,不同参数)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行时运行的时候调用的是确定的方法;

我们通常所说的多态指的都是运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直延迟到运行时才能确定,这也是为什么有时候多态方法又被称为延迟方法的原因;

多态的实现原理

动态绑定和静态绑定

JVM在执行方法时,通常调用的指令有五个,分别是:

invokestatic:调用静态方法;

invokespecial:调用实例构造器方法、私有方法和父类方法;

invokevirtual:调用虚方法;

invokeinterface:调用接口方法,运行时确定具体实现;

invokedynamic:运行时动态解析所引用的方法,然后再执行,用于支持动态类型语言。

其中Invokestatic和invokespecial指令是用于静态绑定,invokevirtual 和 invokeinterface 用于动态绑定。

静态绑定指的是在编译期就能确定的,比如静态方法、构造器、私有方法和父类方法这4种方法在编译期就能解析引用确定的称为非虚方法,与之相对的就是虚方法,对象方法基本都为虚方法,例如某个类的drive(Car car),汽车子类实现类中的run()方法等;有个特例的是被final修饰的方法,由于不能被继承重写,所以是可以唯一确定的,是属于非虚方法,但却是使用invokevirtual指令调用的;

JVM底层多态实现过程

多态的实现过程,本质就是方法调用动态绑定的过程,通过栈帧的信息去找到被调用方法的具体实现,然后使用这个具体实现的直接引用完成方法调用;

invokevirtual指令在运行时解析大致分为以下几个步骤:

  1. 先从操作栈中找到对象的实际类型C;
  2. 找到C中与被调用方法签名相同的方法,如果有访问权限就返回这个方法的直接引用,如果没有访问权限就报错java.lang.IllegalAccessError ;
  3. 如果第2步找不到相符的方法,就去搜索C的父类,按照继承关系自下而上依次执行第2步的操作;
  4. 如果第3步找不到相符的方法,就报错java.lang.AbstractMethodError ;

可以看到,如果子类覆盖了父类的方法,则在多态调用中,动态绑定过程会首先确定实际类型是子类,从而先搜索到子类中的方法;

在程序运行时,动态绑定是一个非常高频的行为,JVM为了提高性能,避免反复搜索对应类型的绑定数据,会建立一个对应的虚方法表和接口方法表,使用对应的表索引来提高查询的性能;

以虚方法表为例,如果某个父类的方法在子类中没有被进行重写,那么此时子类和父类的虚方法表指向的地址是一致的,只有当出现子类重写了父类的方法时,才会出现子类的虚方法表与父类的虚方法表指向的地址不一样。因此如果子类没有重写父类的方法时,会随着父类的方法解析一同解析;

0 人点赞