作者:crane_practice

www.cnblogs.com/crane-practice/p/3671074.html

2019-06-13 08:46:00

Java多态的实现机制是父类或接口定义的引用变量可以指向子类或实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实现对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

浅谈多态机制的意义及实现

在面向对象编程(Object-Oriented Programming, OOP)中,多态机制无疑是其最具特色的功能,甚至可以说,不运用多态的编程不能称之为OOP。这也是为什么有人说,使用面向对象语言的编程和面向对象的编程是两码事。

多态并没有一个严格的定义,维基百科上给它下的定义比较宽松:

Subtype polymorphism, almost universally called just polymorphism in the context of object-oriented programming, is the ability of one type, A, to appear as and be used like another type, B.

一、子类型和子类

这里我想先提一下子类型(Subtype)这个词和子类(Subclass)的区别,简单地说,只要是A类运用了extends关键字实现了对B类的继承,那么我们就可以说Class A是Class B的子类,子类是一个语法层面上的词,只要满足继承的语法,就存在子类关系。

子类型比子类有更严格的要求,它不仅要求有继承的语法,同时要求如果存在子类对父类方法的改写(override),那么改写的内容必须符合父类原本的语义,其被调用后的作用应该和父类实现的效果方向一致。

对二者的对比是想强调一点:只有保证子类都是子类型,多态才有意义。Java父类强制转换子类原则,这篇文章了解下。关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取更多栈长整理的Java技术干货。

二、多态的机制

本质上多态分两种:

编译时多态(又称静态多态)

运行时多态(又称动态多态)

重载(overload)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行时运行的时候调用的是确定的方法。

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

在维基百科中多态的行为被描述为:

The primary usage of polymorphism in industry (object-oriented programming theory) is the ability of objects belonging to different types to respond to method, field, or property calls of the same name, each one according to an appropriate type-specific behavior.

下面简要介绍一下运行时多态(以下简称多态)的机制。

多态通常有两种实现方法:

子类继承父类(extends)

类实现接口(implements)

无论是哪种方法,其核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。

要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,创建的是实际类型。举例来说,假设我们要创建一个ArrayList对象,声明就应该采用这样的语句:

List list = newArrayList();

而不是

ArrayList list = newArrayList();

在定义方法参数时也通常总是应该优先使用父类类型或接口类型,例如某方法应该写成:

public void doSomething(List list);

而不是

public void doSomething(ArrayList list);

这样声明最大的好处在于结构的灵活性:假如某一天我认为ArrayList的特性无法满足我的要求,我希望能够用LinkedList来代替它,那么只需要在对象创建的地方把new ArrayList()改为new LinkedList即可,其它代码一概不用改动。

The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run-time (this is called late binding or dynamic binding).

虚拟机会在执行程序时动态调用实际类的方法,它会通过一种名为动态绑定(又称延迟绑定)的机制自动实现,这个过程对程序员来说是透明的。关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取更多栈长整理的Java技术干货。

三、多态的用途

多态最大的用途我认为在于对设计和架构的复用,更进一步来说,《设计模式》中提倡的针对接口编程而不是针对实现编程就是充分利用多态的典型例子。

定义功能和组件时定义接口,实现可以留到之后的流程中。同时一个接口可以有多个实现,甚至于完全可以在一个设计中同时使用一个接口的多种实现(例如针对ArrayList和LinkedList不同的特性决定究竟采用哪种实现)。

四、多态的实现

下面从虚拟机运行时的角度来简要介绍多态的实现原理,这里以Java虚拟机(Java Virtual Machine, JVM)规范的实现为例。JVM 与 Linux 的内存关系详解,这个推荐大家看一下。关注Java技术栈微信公众号,在后台回复关键字:JVM,可以获取更多栈长整理的JVM技术干货。

在JVM执行Java字节码时,类型信息被存放在方法区中,通常为了优化对象调用方法的速度,方法区的类型信息中增加一个指针,该指针指向一张记录该类方法入口的表(称为方法表),表中的每一项都是指向相应方法的指针。

方法表的构造如下:

由于Java的单继承机制,一个类只能继承一个父类,而所有的类又都继承自Object类。方法表中最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。这里关键的地方在于,如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项,都被认作是父类的方法。

注意这里只有非私有的实例方法才会出现,并且静态方法也不会出现在这里,原因很容易理解:静态方法跟对象无关,可以将方法地址直接引用,而不像实例方法需要间接引用。

更深入地讲,静态方法是由虚拟机指令invokestatic调用的,私有方法和构造函数则是由invokespecial指令调用,只有被invokevirtual和invokeinterface指令调用的方法才会在方法表中出现。

由于以上方法的排列特性(Object——父类——子类),使得方法表的偏移量总是固定的。例如,对于任何类来说,其方法表中equals方法的偏移量总是一个定值,所有继承某父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。

前面说过,方法表中的表项都是指向该类对应方法的指针,这里就开始了多态的实现:

假设Class A是Class B的子类,并且A改写了B的方法method(),那么在B的方法表中,method方法的指针指向的就是B的method方法入口。

而对于A来说,它的方法表中的method方法则会指向其自身的method方法而非其父类的(这在类加载器载入该类时已经保证,同时JVM会保证总是能从对象引用指向正确的类型信息)。

结合方法指针偏移量是固定的以及指针总是指向实际类的方法域,我们不难发现多态的机制就在这里:

在调用方法时,实际上必须首先完成实例方法的符号引用解析,结果是该符号引用被解析为方法表的偏移量。

虚拟机通过对象引用得到方法区中类型信息的入口,查询类的方法表,当将子类对象声明为父类类型时,形式上调用的是父类方法,此时虚拟机会从实际类的方法表(虽然声明的是父类,但是实际上这里的类型信息中存放的是子类的信息)中查找该方法名对应的指针(这里用“查找”实际上是不合适的,前面提到过,方法的偏移量是固定的,所以只需根据偏移量就能获得指针),进而就能指向实际类的方法了。

我们的故事还没有结束,事实上上面的过程仅仅是利用继承实现多态的内部机制,多态的另外一种实现方式:实现接口相比而言就更加复杂,原因在于,Java的单继承保证了类的线性关系,而接口可以同时实现多个,这样光凭偏移量就很难准确获得方法的指针。所以在JVM中,多态的实例方法调用实际上有两种指令:

invokevirtual指令用于调用声明为类的方法;

invokeinterface指令用于调用声明为接口的方法。

当使用invokeinterface指令调用方法时,就不能采用固定偏移量的办法,只能老老实实挨个找了(当然实际实现并不一定如此,JVM规范并没有规定究竟如何实现这种查找,不同的JVM实现可以有不同的优化算法来提高搜索效率)。

我们不难看出,在性能上,调用接口引用的方法通常总是比调用类的引用的方法要慢。这也告诉我们,在类和接口之间优先选择接口作为设计并不总是正确的,当然设计问题不在本文探讨的范围之内,但显然具体问题具体分析仍然不失为更好的选择。

个人见解:多态机制包括静态多态(编译时多态)和动态多态(运行时多态),静态多态比如说重载,动态多态是在编译时不能确定调用哪个方法,得在运行时确定。动态多态的实现方法包括子类继承父类和类实现接口。当多个子类上转型(不知道这么说对不)时,对象掉用的是相应子类的方法,这种实现是与JVM有关的。

关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取更多栈长整理的Java技术干货。

推荐去我的博客:

觉得不错,别忘了点赞+转发哦!

java多态的实现_Java多态的实现机制是什么,写得非常好!相关推荐

  1. java 父类转子类_Java多态,对象转型,和简单工厂模式。希望对您有帮助!

    各位读者老爷们大家好鸭~图图又来了,今天我们要说一下"多态". 怎么理解这两个字呢?可以理解为同一个引用对象的不同表现形态,即将父类的引用指向子类的对象.这是比较官方的书面解释,大 ...

  2. java 多态 降低耦合_java多态

    Java多态就是为了降低耦合,方便我们开发的一种特性. 比如我写了一个动物的接口.然后我通过接口实现了猫和狗这个类. 在我需要使用的时候我可以这样实例化对象 动物 w = new 猫. 这就是向上转型 ...

  3. java父类引用子类_java多态,如何理解父类引用指向子类对象

    要理解多态性,首先要知道什么是"向上转型". 转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求 ...

  4. java 判断object类型_Java多态的6大特性|乐字节

    大家好,我是乐字节的小乐,前几天讲完了Java继承,接下来我们会讲述Java多态. 以上就是本次学习的6大任务.我们依次来看. 一. Object类 Object类是所有Java类的根基类. 如果在类 ...

  5. java的多态代码例子_java 多态实例代码

    多态是同一个行为具有多个不同表现形式或形态的能力.多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现,比如: 在现实中,我们按下F1键这个动作: 如果当前在Flash界 ...

  6. java的多态代码例子_java多态例子,java多态代码实例

    下面要给大家分享的是一个多态经典案例,一起来看看这个java多态简单例子吧./*多态的好处:提高了代码的维护性和扩展性: 弊端:父类不能使用子类的特有功能. 要用子类的特有功能,可以: A:创建子类对 ...

  7. java 多态面试题_java多态面试题

    java多态性 多态分两种: (1) 编译时多态(设计时多态):方法重载. (2) 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态.(我们平时说得多的 ...

  8. java多态知乎_Java多态的理解

    作者:程序狗 链接:https://www.zhihu.com/questio... 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 不请自来,C++的多态不太清楚. ...

  9. java多态强制类型转换_java多态和强制类型转换

    子类可以赋值给超类,称之为向上转型,这个是自动的. 超类不可以赋值给子类,这个是向下转型,需要我们手动实现. 赋值给超类的子类引用在运行期间将表现出不同的特性,这就是多态. 小类型    可转换为   ...

最新文章

  1. python字典遍历的几种方法(for in 用法)
  2. Java 并发编程—核心理论
  3. 关于MFC实现圆角矩形窗口
  4. linux bash -,linux bash 总结
  5. C#模板引擎NVelocity实战项目演练
  6. Java的Reflection机制
  7. android中实现GPS定位功能,Android中实现GPS定位的简单例子
  8. Selenium 生成HTML的测试报告
  9. “项目运行时出错,无法启动调试。绑定句柄无效”的解决办法
  10. java 启动xms_关于java:启动JVM时-Xms和-Xmx参数是什么?
  11. APP推广运营手册全集
  12. 分享一大波高清电子元器件矢量图,速速下载收藏!
  13. OpenCV入门(八)——形态学技术
  14. 2021全新整合单机游戏 PC电脑版中文合集系列下载持续更新
  15. 数据结构银行排队系统c语言,数据结构银行排队系统实验报告
  16. 汽车java歌曲_开车必备100首歌曲 50首适合开车听的歌曲 2019车载歌曲 DJ流行
  17. R语言ROC分析、ROC曲线可视化及最佳阈值计算(threshold、cutoff)
  18. 3d图形学中的uv坐标
  19. 静态博客网页中的网易云音乐播放器
  20. 2022-2027年中国切削刀具市场竞争态势及行业投资前景预测报告

热门文章

  1. bzoj 4942 整数 思考记录
  2. 2017.3.29 longge的问题 失败总结
  3. 【Level 08】U06 Good Feeling L1 End-of-season game
  4. 【Python】理解Python(2) - help() 函数? or 类?
  5. C++开源矩阵计算工具——Eigen 在VS2005中的下载、配置与使用
  6. 华北水利水电大学c语言实验报告八2020,2021年华北水利水电大学级C语言实验报告.doc...
  7. 什么是python 包_什么是python
  8. EL4.1配置文件管理浅谈(1)
  9. ajax实战用法详解
  10. 【分形算法】Jason带你飞之1——LS文法的java实现