Java多态之动态绑定

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

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

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

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

引用变量的类型

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

//假设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对象,而不用做其他的代码调整,动态绑定自动搞定,就相当舒服。

参考书籍:《Thinking in Java》、《Java核心技术卷I》

Java多态之动态绑定的更多相关文章

  1. [Java学习] Java多态和动态绑定

    在Java中,父类的变量可以引用父类的实例,也可以引用子类的实例. 请读者先看一段代码: 1. public class Demo { 2. public static void main(Strin ...

  2. Java多态和动态绑定是如何实现的

    最近深入学习java,看到了动态绑定和多态这一章节,但遗憾的是,大部分的相关文章都停留于表面文字的描述.不得已,最后google了几篇英文文章,在此总结下这个问题. 一.静态绑定和动态绑定的区别 在J ...

  3. 《Java基础知识》Java多态和动态绑定

    在Java中,父类的变量可以引用父类的实例,也可以引用子类的实例. 请读者先看一段代码: public class Demo { public static void main(String[] ar ...

  4. java 多态(动态绑定)

    一.面向对象最核心的机制--动态绑定,也叫多态 1.1.通过下面的例子理解动态绑定,即多态 1 package javastudy.summary; 2 3 class Animal { 4 /** ...

  5. java基础疑难点总结之成员变量的继承,方法重载与重写的区别,多态与动态绑定

    1.成员变量的继承 1.1要点 子类用extends关键字继承父类.子类中可以提供新的方法覆盖父类中的方法.子类中的方法不能直接访问父类中的私有域,子类可以用super关键字调用父类中的方法.在子类中 ...

  6. Java多态与反射

    多态通过分离做什么和怎么做,从另一个角度将接口与实现分离开来:通过多态来消除类型之间的耦合关系,在Java中,多态也叫动态绑定,后期绑定或运行时绑定,那么什么是方法绑定? 方法调用绑定: 将一个方法与 ...

  7. Java 多态——与C++的比较

    学习了Java和C++之后,由于长期不使用C++,而java的基础知识掌握不牢,现在已经搞不清java多态了.现在先来谈谈java多态,稍后有时间再更新C++的多态,并进行比较~ 一. Java的多态 ...

  8. C++和java多态的区别

    C++和java多态的区别 分类: Java2015-06-04 21:38 2人阅读 评论(0) 收藏 举报  转载自:http://www.cnblogs.com/plmnko/archive ...

  9. Java静态绑定与动态绑定

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定. 静态绑定: 在程序执行前方法已经被绑定(也就是说 ...

随机推荐

  1. 理解clientWidth,offsetWidth,clientLeft,offsetLeft,clientX,offsetX,pageX,screenX

    1. clientWidth:表示元素的内部宽度,以像素计.该属性包括内边距,但不包括垂直滚动条(如果有).边框和外边距.(clientWidth = width + padding) 2. offs ...

  2. (C#)WPF:LinearGradientBrush的使用

    在MSDN文档库里可以查到,Rectangle.Fill的类型是Brush.Brush是一个抽象类,凡是以Brush为基类的类都可作为Fill属性的值.Brush的派生类有很多: * SolidCol ...

  3. nyoj 1071-不可以!(a*b + fabs(a*b))

    1071-不可以! 内存限制:64MB 时间限制:1000ms 特判: No 通过数:10 提交数:18 难度:1 题目描述: 判断:两个数x.y的正负性. 要求:不可以使用比较运算符,即" ...

  4. set map symbol

    set 声明 let set = new Set();即创建了一个空的set 赋值 let set = new Set(['张三','李四','王五']); 特性 似于数组,但它的一大特性就是所有元素 ...

  5. Java-selenium

    public class chrometest { public static void main(String[] args) throws InterruptedException { Strin ...

  6. UCACO刷题

    UCACO刷题 SUBMIT: /* ID: your_id_here LANG: C++ TASK: test */ 文件:freopen(“file.in", "r" ...

  7. Beta阶段贡献分配

    此作业要求参见:http://edu.cnblogs.com/campus/nenu/2019fall/homework/10006 队名:扛把子 组长:孙晓宇 组员:宋晓丽 梁梦瑶 韩昊 刘信鹏 要 ...

  8. Java面向对象学习目录

    Java面向对象学习目录 以下为面向对象学习目录,有待补充的部分,我还会再后续的学习过程中加以补充与修改~ 一.面向对象编程思想 二.Java类及类中成员 属性 方法 构造器 代码块 内部类 面向对象 ...

  9. sqlserver2008 R2 安装以后没有 sql server profiler

    一些人在安装好SQL server 2008 r2或者从empress升级到enterprise或者开发版之后没有SQL server profiler功能,如果需要加装则应该找到自己的安装文件(部分 ...

  10. selenium(java)浏览器多窗口切换处理

    要在多个窗口直接切换,首先获取每个窗口的唯一标示符(句柄),通过窗口属性可以获取所有打开窗口的标示符,以集合的形式返回:以下示例:       Set<String> winHandels ...