项目中经常会用到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. SpringMVC详解(四)------SSM三大框架整合之登录功能实现

    为了后面讲解的需要,我们取数据都会从数据库中获取,所以这里先讲讲三大框架(Spring.SpringMVC.MyBatis)的整合.前面讲解 MyBatis 时,写了一篇 MyBatis 和 Spri ...

  2. sizeof求类的大小

    用sizeof求类的大小,http://blog.csdn.net/szchtx/article/details/10254007(sizeof浅析(三)——求类的大小),这篇博文给出了非常详尽的举例 ...

  3. Myeclipse和windows调节成护眼色

    作为程序员,对着电脑屏幕久了,眼睛难免疲劳,下面相信对我们每个 人都很有帮助. windows xp:桌面空白处右键,属性,外观-高级,然后在项目那栏选窗口,再点颜色-其它,然后把色调设为85(默认是 ...

  4. eclipse导入SVN上的Maven多模块项目

    eclipse导入SVN上的Maven多模块项目 博客分类: Eclipse&MyEclipse SVN Maven   一.SVN上Maven多模块项目结构 使用eclipse导入SVN上的 ...

  5. 基于tgp协议的套接字的 粘包解决

    客户端 import socket import struct import json phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM ...

  6. UEditor编辑器第一次赋值失败的解决方法

    网上查了很多方式都不是很好用,最后想到了这样的处理方式 首先在js中定义一个全局变量 var ue = null; 然后在初始化显示编辑器的时候js这样写 if (ue == null) { ue = ...

  7. hdu5673 Robot 卡特兰数 / 默慈金数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5673 分析: 这道题是一道裸的默慈金数,比较容易想到的是用卡特兰数来做.不了解的可以先学习一下. 卡特 ...

  8. GHO2VMDK转换工具分享含VS2010源码

    平常经常用到虚拟机,每次从gho转换为vmdk时都要输入cmd代码,觉得麻烦,自己动手做了个gho2vmdk转换工具,集成ghost32.exe文件,可以一键转换,省时省事.运行时会将ghost32. ...

  9. Servlet和Filter的url匹配以及url-pattern详解 及 filter 循环问题的解决

    Servlet和filter是J2EE开发中常用的技术,使用方便,配置简单,老少皆宜.估计大多数朋友都是直接配置用,也没有关心过具体的细节,今天遇到一个问题,上网查了servlet的规范才发现,ser ...

  10. [2013-06-05]bat脚本设置DNS

    有时候需要切换本机dns,将网络环境转至测试环境 @echo off netsh interface ip set dns name="本地连接" source=static ad ...