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

一、静态绑定和动态绑定的区别

在Java中,当你调用一个方法时,可能会在编译时期(compile time)解析(resolve),也可能实在运行时期(runtime)解析,这全取决于到底是一个静态方法(static method)还是一个虚方法(virtual method)。如果是在编译时期解析,那么就称之为静态绑定(static binding),如果方法的调用是在运行时期解析,那就是动态绑定(dynamic binding)或者延迟绑定(late binding)。Java是一门面向对象的编程语言,优势就在于支持多态(Polymorphism)。多态使得父类型的引用变量可以引用子类型的对象。如果调用子类型对象的一个虚方法(非private,final or static),编译器将无法找到真正需要调用的方法,因为它可能是定义在父类型中的方法,也可能是在子类型中被重写(override)的方法,这种情形,只能在运行时进行解析,因为只有在运行时期,才能明确具体的对象到底是什么。这也是我们俗称的运行时或动态绑定(runtime or dynamic binding)。另一方面,private static和final方法将在编译时解析,因为编译器知道它们不能被重写,所有可能的方法都被定义在了一个类中,这些方法只能通过此类的引用变量进行调用。这叫做静态绑定或编译时绑定(static or compile time binding)。所有的private,static和final方法都通过静态绑定进行解析。这两个概念的关系,与“方法重载”(overloading,静态绑定)和“方法重写”(overriding,动态绑定)类似。动态绑定只有在重写可能存在时才会用到,而重载的方法在编译时期即可确定(这是因为它们总是定义在同一个类里面)

总而言之,其区别如下:

①静态绑定在编译时期,动态绑定在运行时期。

②静态绑定只用到类型信息,方法的解析根据引用变量的类型决定,而动态绑定则根据实际引用的的对象决定

③在java中,private static 和 final 方法都是静态绑定,只有虚方法才是动态绑定

④多态是通过动态绑定实现的。

二、动态绑定是如何实现的?

一个对象的多态方法的地址将被存储在该对象的方法表(method table)里面。在运行时期,调用多态方法的时候,JVM会在此表中搜索方法的名字,从而获取方法的地址。方法表里包含方法的名字和对应的地址(注意,这个地址是动态绑定的)。这个方法表对所有属于这个类的对象而言,都是一样的,所以它会存储在Class对象中(这里对象类型以Integer为例)(在其他的语言中,这样的表又叫做vtables,虚函数表)。需要说明的是,java语言中,如果没有添加任何关键字,则方法默认就是虚方法,任何子类都可以重写它。

方法表并不属于语言的一部分,但是会有很多种不同的实现(不同的JVM提供商可以自由选择实现的细节,只要结果保证一致就ok)。其中,Sun公司的JVM实现,则选择了将方法表入口放在对象的常量池(constant pool)里,你可以使用命令java -verbose foo来查看。(所有的属于同一个类型的对象都将拥有同一个方法表,JVM也可以将其放在别的地方)

下面,将通过一个图表实例来展示,对于某些类(这里以Integer为例)而言,是如何一步步构建方法表的。初始时,表都是空的。运行时,方法表将从最远的祖先类开始,逐步加入这些多态方法。通常,这个最远的祖先是Object类。

           方法名      地址                           注释
     Object.toString             111          Object.toString method address    
              ...       ...                 10个其他的方法

接下来,这个表中将加入第二远的祖先类的多态方法,如果已经存在,就修改其地址值。此例中,第二远的类是Number类。如果你查看了javadoc,你就会发现Number类并没有重写任何方法,只是额外多了六个方法,因而,将这六个多的方法加入表中。此时,toString项并没有被改变,方法表如下:

方法名 地址 注释
Object.toString 111 Number.toString method address
Number.intValue 222 Number.intValue method address
... ... 15个其他的方法

这个过程一直持续下去,直到所有的父类的多态方法都被合并进这个表里。最后,方法表会被Integer类的多态方法所更新,此时,toString方法会被重写:

方法名 地址 注释
Object.toString 333 Integer.toString method address
Number.intValue 444 interger.intValue method address
Integer.parseInt 555 Number.longValue method address
... ... 其他的一些方法

方法表中的方法名这一项,只包含最初始的类名,所谓重写,只是修改了地址栏下的值,不会改变方法名的值。所以,如果用javap指令查看多态方法名,只会显示Object.toString,而不是toString或者Integer.toString。

需要说明的是,此处,假如有Number num = new Integer(10),即便方法表里面有了Integer.parseInt方法,我们仍不能通过num来调用parseInt。也就是说,num变量引用了Integer对象,并且与上述方法表关联,但在编译时期时,编译器会根据语法规则,实行访问控制,num不能调用和访问独属于Integer的类方法,只能访问自己拥有访问权限的类方法,而这些方法中的某些方法,在运行过程中,名字未变,映射地址却发生了变化,因而调用的是所引用的子类Integer的实现。这点要弄清楚!

Java多态和动态绑定是如何实现的的更多相关文章

  1. Java多态之动态绑定

    目录 Java多态之动态绑定 引用变量的类型 编译时类型 运行时类型 方法绑定 静态绑定 动态绑定 方法表 Java多态之动态绑定 上篇回顾:多态是面向对象程序设计非常重要的特性,它让程序拥有 更好的 ...

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

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

  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. gwy常识

    其实公务员考试是一门艺术,七分靠水平,三分凭发挥,充分而又细致的准备则是取得优秀成绩的前提.考生若想在笔试中成功上岸,还需苦练内功,凭技巧和真才实学在考场上一较高下.那么针对历年上海公务员考试笔试考情 ...

  2. 静态call 动态call LINK

    COBOL的调用可以是静态调用(Static Call),这时,被调用的子程序必须与调用程序一起链接(link-edited)起来形成一个完整的装载模块(Load module),但子程序依然可以单独 ...

  3. MTK平台源码 mt6589-jb3-x_20131122

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha

  4. 【扫描线】Gym - 101190E - Expect to Wait

    假设初始人数为0, 将每个时刻在等待的人数写下来,就是求个和. 如果纵坐标看成人数,横坐标看成时间,就是求个面积. 因为初始人数不一定为零,所以离线后扫描线即可回答所有询问. #include< ...

  5. 【数论】【ex-BSGS】poj3243 Clever Y

    用于求解高次同余方程A^x≡B(mod C),其中C不一定是素数. http://blog.csdn.net/tsaid/article/details/7354716 这篇题解写得最好. 那啥,这题 ...

  6. java之判断输入的数是否为素数

    import java.util.Scanner; public class TestIsSushu { public static void main(String[] args) { Scanne ...

  7. ubuntu BCM43142 lenovo网卡驱动安装(Broadcom)

    ubuntu13.10 lenovo网卡驱动安装(Broadcom)   ubuntu当月刚出了13.10版本,在升级了操作系统版本后无法搜索无线热点,联想官网提供的驱动下载都是为windows准备的 ...

  8. ScrewTurn Wiki 详细安装(.net 版本下的免费wiki) 步骤

    首先看下官网: http://www.sunhorizon.info/Default.aspx  1.下载和安装                                            ...

  9. kubernetes HA 脚本

    集群方案: 发行版:CentOS 7 版本: Kubernetes:1.9.1 master高可用方案:keepalived LVS 网络方案:Flannel Master HA 四步骤: 1. 安装 ...

  10. SqlServer_游标循环

    --从游标取的值 ) ) --获取待返现数据,并循环处理 DECLARE TestCursor CURSOR FOR SELECT ID,UserName FROM dbo.UserInfo Open ...