多态:程序绑定(动态绑定与静态绑定)

多态是一个运行时的行为,不是编译时行为。

程序绑定的概念:

绑定指的是一个方法的调用与方法所在的类或对象(方法主体)关联起来。对java来说,绑定分为静态绑定和动态绑定;或者叫做前期绑定和后期绑定。

静态绑定(前期绑定):

在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。发生在编译阶段,绑定的是类信息,即为定义的类的类型
针对java简单的可以理解为程序编译期的绑定;这里特别说明一点,java当中的方法,只有final,static,private,重载方法(overloaded methods)和构造方法是静态绑定
所有的变量都是静态绑定。

动态绑定(后期绑定):

在运行时根据具体对象的类型进行绑定。发生在运行阶段,绑定的是对象信息。
若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息。
重写方法(overridden methods)使用的是动态绑定

动态绑定的过程:

  • 虚拟机提取对象实际类型的方法表;
  • 虚拟机搜索方法签名;
  • 调用方法。
  1. 编译器检查对象的声明类型和方法名。
    假设我们调用p.method()方法,并且p已经被声明为Child类型,那么编译器会列举出Child类中所有的名称为method的方法和从Child类的父类继承过来的method方法,如果发现子类重写了父类的方法,则父类方法被覆盖。
  2. 接下来编译器检查方法调用中提供的参数类型。如果在所有名称为method的方法中有一个参数类型和调用提供的参数类型最为匹配,那么就调用这个方法,这个过程叫做“重载解析”
    重载解析会匹配最精确的一个,一个方法或构造器可以接受传递给另一个方法或构造器的任何参数,那么我们就说第一个比第二个方法缺乏精确性[JLS 15.12.2.5]。
  3. 当程序运行并且使用动态绑定调用方法时,虚拟机必须调用同p所指向的对象的实际类型相匹配的方法版本。假设child类定义了mehod()那么该方法被调用,否则就在child的父类(Parent类)中。
  4. 动态绑定时,参数会自动进行向上类型,但不会进行向下类型转换。

补充

这里容易混淆的点是静态绑定和动态绑定的区分,以及到底我们写的代码会调用什么方法,这里写了一个 Test 以供分析:
DynamicBingingTest.java

特别说明的一点是,private声明的方法和成员变量不能被子类继承,所有的private方法都被隐式的指定为final的,所以是静态绑定的。(由此我们也可以知道:将方法声明为final类型的一是为了防止方法被覆盖,二是为了有效的关闭java中的动态绑定)。

Java泛型会被抹除,但是编译阶段已经确保了泛型类型正确(但是 newInstance()方式可以Bug般地绕过泛型检查)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,874评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,273评论 19 139
  • 程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。对java来说,绑定分为静态绑定和动...
    Mr_chong阅读 1,361评论 0 7
  • 在安装编译某些node模块时,需要Python2.7和gcc4.8编译环境,为了不影响别的代码程序,需要在不更新的...
    驳斑阅读 1,696评论 0 1
  • 我们的人生终极目标或许是成功,或许是家庭幸福,或许是自在生活,但是,我们却从未意识到:成功并不难,而在于少犯错误。...
    海阔天空1221阅读 202评论 0 0