面向对象编程有三大特性:封装、继承、多态。

封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。

继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。同时继承也为实现多态做了铺垫。那么什么是多态呢?多态的实现机制又是什么?请看我一一为你揭开。

多态

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:

酒 a = 剑南春

酒 b = 五粮液

酒 c = 酒鬼酒

这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。

诚然,要理解多态我们就必须要明白什么是“向上转型”。在继承中我们简单介绍了向上转型,这里就在啰嗦下:在上面的喝酒例子中,酒(Win)是父类,剑南春(JNC)、五粮液(WLY)、酒鬼酒(JGJ)是子类。我们定义如下代码:

JNC a = new JNC();

对于这个代码我们非常容易理解无非就是实例化了一个剑南春的对象嘛!但是这样呢?

Wine a = new JNC();

在这里我们这样理解,这里定义了一个Wine 类型的a,它指向JNC对象实例。由于JNC是继承与Wine,所以JNC可以自动向上转型为Wine,所以a是可以指向JNC实例对象的。这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。

但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了---1。

1 public classWine {2 public voidfun1(){3 System.out.println("Wine 的Fun.....");4 fun2();5 }6

7 public voidfun2(){8 System.out.println("Wine 的Fun2...");9 }10 }11

12 public class JNC extendsWine{13 /**

14 * @desc 子类重写父类方法15 * 父类中不存在该方法,向上转型后,父类是不能引用该方法的16 *@parama17 *@returnvoid18 */

19 public voidfun1(String a){20 System.out.println("JNC 的 Fun1...");21 fun2();22 }23

24 /**

25 * 子类重写父类方法26 * 指向子类的父类引用调用fun2时,必定是调用该方法27 */

28 public voidfun2(){29 System.out.println("JNC 的Fun2...");30 }31 }32

33 public classTest {34 public static voidmain(String[] args) {35 Wine a = newJNC();36 a.fun1();37 }38 }39 -------------------------------------------------

40 Output:41 Wine 的Fun.....42 JNC 的Fun2...

从程序的运行结果中我们发现,a.fun1()首先是运行父类Wine中的fun1().然后再运行子类JNC中的fun2()。

分析:在这个程序中子类JNC重载了父类Wine的方法fun1(),重写fun2(),而且重载后的fun1(String a)与 fun1()不是同一个方法,由于父类中没有该方法,向上转型后会丢失该方法,所以执行JNC的Wine类型引用是不能引用fun1(String a)方法。而子类JNC重写了fun2() ,那么指向JNC的Wine引用会调用JNC中fun2()方法。

所以对于多态我们可以总结如下:

指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

多态的实现

实现条件

在刚刚开始就提到了继承在为多态的实现做了准备。子类Child继承父类Father,我们可以编写一个指向子类的父类类型引用,该引用既可以处理父类Father对象,也可以处理子类Child对象,当相同的消息发送给子类或者父类对象时,该对象就会根据自己所属的引用而执行不同的行为,这就是多态。即多态性就是相同的消息使得不同的类做出不同的响应。

Java实现多态有三个必要条件:继承、重写、向上转型。

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

实现形式

在Java中有两种形式可以实现多态。继承和接口。

基于继承实现的多态

基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。

1 public classWine {2 privateString name;3

4 publicString getName() {5 returnname;6 }7

8 public voidsetName(String name) {9 this.name =name;10 }11

12 publicWine(){13 }14

15 publicString drink(){16 return "喝的是 " +getName();17 }18

19 /**

20 * 重写toString()21 */

22 publicString toString(){23 return null;24 }25 }26

27 public class JNC extendsWine{28 publicJNC(){29 setName("JNC");30 }31

32 /**

33 * 重写父类方法,实现多态34 */

35 publicString drink(){36 return "喝的是 " +getName();37 }38

39 /**

40 * 重写toString()41 */

42 publicString toString(){43 return "Wine : " +getName();44 }45 }46

47 public class JGJ extendsWine{48 publicJGJ(){49 setName("JGJ");50 }51

52 /**

53 * 重写父类方法,实现多态54 */

55 publicString drink(){56 return "喝的是 " +getName();57 }58

59 /**

60 * 重写toString()61 */

62 publicString toString(){63 return "Wine : " +getName();64 }65 }66

67 public classTest {68 public static voidmain(String[] args) {69 //定义父类数组

70 Wine[] wines = new Wine[2];71 //定义两个子类

72 JNC jnc = newJNC();73 JGJ jgj = newJGJ();74

75 //父类引用子类对象

76 wines[0] =jnc;77 wines[1] =jgj;78

79 for(int i = 0 ; i < 2 ; i++){80 System.out.println(wines[i].toString() + "--" +wines[i].drink());81 }82 System.out.println("-------------------------------");83

84 }85 }86 OUTPUT:87 Wine : JNC--喝的是 JNC88 Wine : JGJ--喝的是 JGJ89 -------------------------------

在上面的代码中JNC、JGJ继承Wine,并且重写了drink()、toString()方法,程序运行结果是调用子类中方法,输出JNC、JGJ的名称,这就是多态的表现。不同的对象可以执行相同的行为,但是他们都需要通过自己的实现方式来执行,这就要得益于向上转型了。

所以基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。

如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。

基于接口实现的多态

继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。

在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。

继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。

如 Map map =new HashMap ; List list=new ArraryList 都是基于接口实现的多态。

经典实例

1 public classA {2 publicString show(D obj) {3 return ("A and D");4 }5

6 publicString show(A obj) {7 return ("A and A");8 }9

10 }11

12 public class B extendsA{13 publicString show(B obj){14 return ("B and B");15 }16

17 publicString show(A obj){18 return ("B and A");19 }20 }21

22 public class C extendsB{23

24 }25

26 public class D extendsB{27

28 }29

30 public classTest {31 public static voidmain(String[] args) {32 A a1 = newA();33 A a2 = newB();34 B b = newB();35 C c = newC();36 D d = newD();37

38 System.out.println("1--" +a1.show(b));39 System.out.println("2--" +a1.show(c));40 System.out.println("3--" +a1.show(d));41 System.out.println("4--" +a2.show(b));42 System.out.println("5--" +a2.show(c));43 System.out.println("6--" +a2.show(d));44 System.out.println("7--" +b.show(b));45 System.out.println("8--" +b.show(c));46 System.out.println("9--" +b.show(d));47 }48 }

运行结果:

1 1--A and A2 2--A and A3 3--A and D4 4--B and A5 5--B and A6 6--A and D7 7--B and B8 8--B and B9 9--A and D

java多态基础_java基础(三)-----java的三大特性之多态相关推荐

  1. polymorphism java_Java基础-面向对象第三大特性之多态(polymorphism)

    Java基础-面向对象第三大特性之多态(polymorphism) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多态概述 多态是继封装,继承之后,面向对象的第三大特性,多态的 ...

  2. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  3. 面向对象的三大特性之多态

    面向对象的三大特性之多态 文章目录 面向对象的三大特性之多态 前言 一.静态多态 1.函数重载 2.函数模板 二.动态多态 1.函数重写 2.虚函数的继承特性 三.重定义 前言 多态的简单定义为同一种 ...

  4. Java基础篇——三大特性(多态)

    这是Java三大特性的最后一篇文章,本篇主要讲解多态的概念和应用.如果是对Java有兴趣的小伙伴可以关注一下,后续会推出一系列的Java基础和进阶的总结(或者说是个人的理解吧!)可以让你学到一些基础但 ...

  5. java super用法_Java基础面试题汇总

    blog.csdn.net/ThinkWon/article/details/104390612 Java概述 何为编程 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结 ...

  6. java 方法泛型_Java基础学习,什么是泛型概念,使用泛型有哪些好处?

    一般的类和方法,只能使用具体的类型,要么是基础数据类型,要么是自定义类. 如果要编写可以应用与多种类型的代码,这种刻板的限制对代码的束缚就会很大. 泛型的字面概念: 适合用于许多类型. 在面向对象中, ...

  7. java 5 多线程_Java基础系列五、多线程

    1.什么是进程?什么是线程? 进程概念:在计算机中运行的软件,是操作系统中最基础的组成部分 .进程是容器,里面装的都是线程. 线程概念:就是运行在进程中的一段代码,是进程中最小组织单元. 注意: 1. ...

  8. java选填_java基础填空选择题

    Core Java试题 选择填空题:全部为多选题,只有全部正确才能得分. 1. 编译java程序的命令是__B_;运行java程序的命令是____A____;产生java文挡的命令是_____D___ ...

  9. 在java中蓝色_Java基础

    cmd命令符 dir:显示当前文件夹下的子文件 cd..:后退上一级的文件 cd 子文件:跳到子文件 cd/:直接跳到根目录 盘符: :跳到相关盘 万能的Tab键:补齐 Java环境配置 1.官网下载 ...

最新文章

  1. 基于OpenCV提取特定区域
  2. AJAX实现页面选项卡、隔行换色、弹出层功能代码
  3. WCF for .NET CF的一个应用及两个困惑的问题
  4. mongodb 导出到sqlserver_迁移sqlserver数据到MongoDb的方法
  5. tomcat php模块化运行,Windows下 Tomcat 运行 PHP 的配置
  6. mapreduce笔记
  7. linux挂载固硬盘装,linux下安装新硬盘并挂载mount
  8. mysql 服务无法启动 没有报告任何错误_My SQL学习之路(一)
  9. 如何在android进行ltp测试,Android系统完整性度量架构IMA-EVM
  10. 网络分析仪-inSSIDer
  11. 量子计算计算机简史pdf,量子计算及其潜在应用.pdf
  12. PATH变量,cp,mv,cat,more,less,head,tail命令举例
  13. Oracle查看分区、索引、表占用空间大小
  14. SQL:pgsql查询一段时间内每个小时的首条数据,为空返回0
  15. Python获取矢量文件属性表字段及类型
  16. 【Wifi密码破解】安卓手机、电脑如何破解Wifi密码
  17. coreldraw怎么改成半圆形_cdr怎么把图形修剪成指定的形状?
  18. smbrun - smbd和外部程序间的接口程序。
  19. win10查看计算机系统版本,Win10版本怎么看?Win10系统版本查看方法
  20. LTspice - 基本操作

热门文章

  1. 二维码扫码登录的项目实战(建议收藏)
  2. 黑客落网记:FBI如何抓捕Anonymous核心成员
  3. uniapp兼容保利威视频,可编译成微信小程序、移动端、h5
  4. VMware安装winows/linux虚拟机
  5. ES6:export default 和 export 区别
  6. 程序的本质(指令、数据及其组织形式);线程、进程的作用及其运行机制和区别
  7. Unity UGUI 性能优化
  8. 第二章 nRF52832介绍
  9. 关于NodeMCU烧写的坑(load 0x33333333, len 858993459, room 0)
  10. Android MI2S和PCM简要介绍