Java多态中动态绑定的原理
创始人
2024-12-24 14:42:34
0次

多态是面向对象程序设计非常重要的特性,它让程序拥有 更好的可读性和可扩展性。

发生在继承关系中。  需要子类重写父类的方法。  父类类型的引用指向子类类型的对象。

自始至终,多态都是对于方法而言,对于类中的成员变量,没有多态的说法。

一个基类的引用变量接收不同子类的对象将会调用子类对应的方法,这其实就是动态绑定的过程。在理解动态绑定之前,先补充一些概念。

引用变量的类型

引用类型的变量具有两种类型:编译时类型和运行时类型。(也分别叫做声明类型和实际类型)举个简单的例子:

//假设Student类是Person类的子类Person p = new Student();

编译时类型

也叫声明类型,即由声明变量时的类型所决定。  上式的Person即为引用变量p的编译时类型。

运行时类型

也叫实际类型,即由指向对象的实际类型所决定。  上式的Student即为引用变量p的运行时类型。

方法绑定

将方法调用同方法主体关联起来被称为绑定。

静态绑定

在程序执行前进行绑定,叫做静态绑定,也称作前期绑定。在面向过程的语言中是默认的绑定方式。

在Java中,用private、static和final修饰的方法(static和final之后会做出总结)或构造器能够准确地让编译器调用哪个方法,就是静态绑定(static binding)。

动态绑定

在运行时根据对象的运行时类型进行绑定,叫做动态绑定,也叫做后期绑定。当然在Java中,除了静态绑定的那些方法,其他方法的调用方式就是动态绑定啦。

public class DynamicBinding {  //Object是所有类的超类,根据向上转型,该方法可以接受任何类型的对象  public static void test(Object x) {    System.out.println(x.toString());  }  public static void main(String[] args) {    test(new PrimaryStudent());//Student    test(new Student());//Student    test(new Person());//Person    test(new Object());//java.lang.Object@1b6d3586  }}class Person extends Object {  @Override  public String toString() {    return "Person";  }  public void run(){}  public void count(int a){}}class Student extends Person {  @Override  public String toString() {    return "Student";  }  public void jump(){}}class PrimaryStudent extends Student {}

四句调用方法的语句中的形参,编译时类型都是Object。注意:引用变量只能调用编译时类型所具有的方法。

它们运行时类型各不相同,所以解释运行器在运行时,会调用它们各自类型中重写的方法。

相同的类型的引用变量,在调用同一个方法时,表现出不同的行为特征,这就是多态最直观的体现吧。

方法表

我们还可以发现,test(new PrimaryStudent());的运行结果是Student,,结果很明显,因为PrimaryStudent类中并没有重写父类的方法,如果采用动态绑定的方式调用方法,虚拟机会首先在本类中寻找适合的方法,如果没有,会一直向父类寻找,直到找到为止。

那么,每次调用时都要向上寻找,时间开销必然会很大。为此虚拟机预先为每个类都创建了方法表,其中列出了所有的方法签名(返回值类型不算)和实际调用的方法,这样子的话,在调用方法时直接查表就可以了。(值得一提的是,如果用super限定调用父类方法,那么将直接在实际类型的父类的表中查找)

下面是Person类的方法表:

Person:  //下面省略Object方法签名  //xxx()-> Object.xxx()  //方法签名->实际调用的方法  toString()->Person.toString()  run()->Person.run()  count(int)->Person(int)

下面是Student类的方法表:

Student:  //下面省略Object方法签名  //xxx()-> Object.xxx()  //方法签名->实际调用的方法  toString()->Student.toString()  jump()->Student.jump()  run()->Person.run()  count(int)->Person(int)

下面是PrimaryStudent类的方法表(PrimaryStudent类为空,直接继承Student类):

PrimaryStudentt:  //下面省略Object方法签名  //xxx()-> Object.xxx()  //方法签名->实际调用的方法  toString()->Student.toString()  jump()->Student.jump()  run()->Person.run()  count(int)->Person(int)

因此,在执行test(new PrimaryStudent());语句时,虚拟机将会提取PrimaryStudent的方法表。

虚拟机将会在表中搜索定义toString签名的类。这时虚拟机已经知道需要调用Student类型的toString()方法。

最后,调用方法,完毕。

动态绑定大大提升了程序的可扩展性,比如,我现在要新增一个Teacher类,可以直接让Teacher类继承于Person类,再用

Object类的引用指向Teacher对象,而不用做其他的代码调整,动态绑定自动搞定,就相当舒服。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...