项目中经常会用到java多态这个特性,之前只知道一些皮毛,现在发现自己对它并没有一个系统的认识,想从新梳理下自己的基础库。

看了java编程思想中对象导论,关于继承的描述:java中的类型不仅仅只是描述了作用于一个对象集合上的约束条件,同时还有与其他类型的之间的关系。可以创建一个基类来表示系统中某些对象的核心概念,从基类的基础上导出其他的类型,用以表示此核心可以被实现的不同方式。因此我们知道了类与类之间还有继承的关系。

问题:那什么是多态呢?多态跟继承有什么关系?

假设我编写了一个基类,它有多个导出类, 每次因我们调用导出类的方法而创建自己对象时,n多个导出类有可能创建n个导出类对象。

java中多态给我们带来的好处是可以不用创建具体的导出类对象,而是基类的对象,去调用各自的方法。这种情形在书中描述的是:在处理类型层次结构时,经常想把一个对象不当做它所属的特定类型对待,而是当做基类对象对待。

例如:SAO是一个基类,AliSAO和WeixinSAO是其导出类,都有一个相同的hello方法

按照自己之前老套路就是:

AliSAO aliSAO = new AliSAO();

aliSAO .hello();

... ...

如果有n个导出类,就会有n个不同类型的对象

... ...

现在把导出类的类型改成基类,交由java这种多态,使得我们可以编写出不依赖特定类型的编码。  

SAO aliSAO = new AliSAO();
SAO weixinSAO = new WeixinSAO();

aliSAO.hello()和weixinSAO.hello()

aliSAO和weixinSAO对象可以统一用 SAO类型

这样的代码是受新添加代码影响较小。

但是这样子会引出一个问题:把导出类对象当做泛化的基类类型对象,此对象本身怎么确定去执行正确的方法呢?

一个非面向对象编程的编译器产生的函数调用会引起所谓的前期绑定,编译器将产生一个具体的函数名称的调用,运行时这个调用会解析到具体代码的绝对地址上.而不会出现像java这种泛化对象的不确定性方法调用。

如果是private、static、final 方法或者是构造器,则编译器明确地知道要调用哪儿个方法,这种调用方式成为“静态调用”.动态绑定只是针对对象的非private,static,final方法.

而面向对象编程中,这种情形在编译期间是无法确定具体调用那个方法的,SAO类型对象(aliSAO和weixinSAO )在没有运行时不能确定它具体类型(有人觉得SAO aliSAO = new AliSAO();不就能知道是AliSAO类型泛化的,此时是在编译期间,对象都没有创建,虚拟机根本不知道,好比你自己心里想的自己很清楚,你想让别人知道,首先你得说出来,这个说出来就是运行),hello()方法都不知道调用自己的SAO对象是基类还是导出类。

为了解决这个问题面向对象程序设计语言提出了后期绑定的概念:java使用一小段代码代替了绝对地址调用,这段代码使用了对象中存储的信息来计算方法的地址.

这样一来,每个对象根据这段代码的内容,可以具有不同的行为表现,当向一个对象发送消息时,该对象就能够做出相应的应答.

上面说的都是实例方法,如果是类的静态属性和静态方法能否继承?

答案是可以的.只是这种继承有个特性,叫隐藏.当子类属性和方法跟父类相同时,会出现隐藏现象.如下图:

java的多态之所以能现实是依赖于父子类继承,接口实现,重写和重载.有了继承,可以通过子类对象指向父类引用,有了重写,可以通过父类引用的子类对象访问子类重写的方法,而不是父类的方法,这是因为“重写”后子类的方法优先级要高于父类的优先级.而隐藏却没有这个属性,因此在如图中通过Parent ps = new Son();ps.getName()是非静态方法,调用的是子类重写的方法,ps.getAge()是静态方法,只能调用父类的方法!

切记上面说的导出类继承基类方法的覆盖后,导出类的非静态的方法优先级要高,如果是属性呢?

如果注意到了:

Parent ps = new Son();
System.out.println(ps.age);// 返回父类的age=30

System.out.println(ps.money);// 返回父类的money=500

System.err.println(ps.name);// 'jack'

其中age和money在基类和导出类中都是静态变量.而name是非静态变量.

就会知道基类与导出类的属性覆盖是没有优先级的,获取的都是基类的属性值.它跟具体对象类型是没关系的,只跟对象引用类型有关!

重写只是发生在父子类继承的的方法中,属性是没有重写这一说法的.当导出类有和基类相同 名称的属性时(甚至类型都可以不同)基类的属性会被隐藏

对于子类来说,父类的属性是不能被子类对象引用访问到的,而需要通过其父类对象的引用访问;通常来说,我们不建议隐藏属性,因为这会使代码不易阅读;

从以上定义可以看出,成员属性不能像方法那样被重写,当子类定义了一个和其父类相同名字的成员属性,子类仅仅是声明了一个新的属性,而其父类的属性被隐藏起来,这不是重写,实际上用super.属性名,还是可以得到父类的非private属性,所以不能以多态的形式访问。

用一句话总结:在Java中,属性绑定到类型,方法绑定到对象!

用自己的话理解隐藏就是:当导出类中有与基类中属性相同名称或者private,static,final或构造方法等签名(方法名称+方法参数)相同时,注意前提条件是两者有继承关系且基类引用是由导出类对象实例化,如果不是有导出类对象实例化基类类型,则不会出现此情况.隐藏相当于导出类的实例对象去掉了基类的属性和方法,如下图,即对象不具备这种能力了,只能去访问基类对应的属性或方法!

效果类似:

向上转型:将导出类看成是基类的过程就是向上转型,前面提到的SAO aliSAO = new AliSAO();即是向上转型,其实际对象是AliSAO导出类的对象,引用的却是是基类.

只能导出类对象向上转型基类对象,反之则不能(如果基类对象能转型成导出类对象,会出现该对象丢失导出类的行为或属性,毕竟导出类的属性和方法要等于或多于基类).

java继承涉及的动/静态绑定及隐藏的更多相关文章

  1. Java继承之方法重写

    目录 Java继承之方法重写 代码体现 概念 注意事项 "两同两小一大" 其他注意点 重写与重载 @Override注解 Java继承之方法重写 在Java继承中,子类可以获得父类 ...

  2. 「万字图文」史上最姨母级Java继承详解

    摘要:继承是面向对象软件技术中的一个概念.它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用. 本文分享自华为云社区<「万字图文」史上最姨母级Java继承详解丨[奔跑吧!JAVA] ...

  3. Java 继承02

    向上类型转换 父类型的引用指向子类型的实例. Person p = new Person();Animal a = p; //子类对象赋值给父类类型的变量 注意: 向上转型后,子类单独定义的方法会丢失 ...

  4. Java继承与组合

    Java继承与组合 继承 java 中使用extends关键字表示继承关系,当创建一个类时,如果没有明确指出要继承的类,则是隐式地从根类Object进行继承. 子类继承父类的成员变量 子类能够继承父类 ...

  5. Java—继承、封装、抽象、多态

    类.对象和包 1) 面向对象编程(Object Oriented Programming ,简称 OOP):20世纪70年代以后开始流行. 2) 结构化编程与面向对象编程的区别: A. 在结构化编程中 ...

  6. Java - 20 Java 继承

    Java 继承 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类.继承可以理解为一个对象从另一个对象获取属性的过程. 如果类A是类B的父类,而类B是类C的父类,我们也称C是A的子 ...

  7. Java继承相关知识总结

    Java继承的理解 一.概念: 一个新类从已有的类那里获得其已有的属性和方法,这种现象叫类的继承 这个新类称为子类,或派生类,已有的那个类叫做父类,或基类 继承的好处:代码得到极大的重用.形成一种类的 ...

  8. Java 继承和多态

                                                        Java  继承和多态 Java 继承 继承的概念 继承是java面向对象编程技术的一块基石,因 ...

  9. 【笔试题】Java 继承知识点检测

    笔试题 Java 继承知识点检测 Question 1 Output of following Java Program? class Base { public void show() { Syst ...

随机推荐

  1. Python 序列的修改、散列和切片

    Vector类:用户定义的序列类型 我们将使用组合模式实现 Vector 类,而不使用继承.向量的分量存储在浮点数数组中,而且还将实现不可变扁平序列所需的方法. p.p1 { margin: 0.0p ...

  2. Razor Page–Asp.Net Core 2.0新功能

    Razor Page介绍 前言 上周期待已久的Asp.Net Core 2.0提前发布了,一下子Net圈热闹了起来,2.0带来了很多新的特性和新的功能,其中Razor Page引起我的关注,作为web ...

  3. python编码错误

    初学python,遇到的最难忘的坑没有之一.这个问题起码困扰了我一周.在我写了一段代码之后经常遇见这样的报错. 本质原因是我用的python2,在编码流派中python2是比较奇葩的一派,不随大流.所 ...

  4. Linux桌面环境GNOME实用技巧

    GNOME是Linux桌面上主流的集成桌面环境之一,GNOME桌面以其风格简洁.操作便捷而受到Linux用户的欢迎.这里将介绍Linux桌面环境GNOME的操作技巧,在这里拿出来和大家分享一下. 下面 ...

  5. GUI RedHat7中常用的一些设置

    GUI RedHat7中常用的一些设置... ------------------ RedHat7更改桌面背景 ================= 更改RedHat7的分辨率 ============ ...

  6. AOP 面向切面的编程

    一.面向切面的编程需求的产生 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀.每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点. 代码分散: 以日志需求为例,只是为了 ...

  7. Java对象中的finalize()方法使用说明

    我在写java程序的时候,从来没有遇见过是用Object.finalize()的时候,但是在学习Java虚拟机的垃圾回收机制时,虚拟机在进行垃圾回收时需要使用finalize()方法来进行对象清理.下 ...

  8. [知了堂学习笔记]_纯JS制作《飞机大战》游戏_第1讲(实现思路与游戏界面的实现)

    整体效果展示: 一.实现思路 如图,这是我完成该项目的一个逻辑图,也是一个功能模块完成的顺序图. 游戏界面的完成 英雄飞机对象实现,在实现发射子弹方法过程中,又引出了子弹对象并实现.在此时,英雄飞机能 ...

  9. Ubuntu14.04下搭建VPN服务 -pptp

    在Ubantu下采用PPTP搭建VPN,优点是配置简单快捷.本教程亲自测试,熟练了在新机器上5分钟搞定VPN. - - - - - - - - - - - - - - - - - - - - - - ...

  10. Android检查更新下载安装

    检查更新是任何app都会用到功能,任何一个app都不可能第一个版本就能把所有的需求都能实现,通过不断的挖掘需求迭代才能使app变的越来越好.检查更新自动下载安装分以下几个步骤: 请求服务器判断是否有最 ...