新的一周,新的干货分享

大家知道,面向对象有三个特征:继承、封装和多态。现在,我们谈谈关于继承的一些问题。了解一下继承的优点、缺点,以及继承缺点的解决方案。

继承的起源,来自于多个类中相同特征和行为的抽象。子类可以通过继承父类,那么可以调用父类中定义的方法和属性,从而达到代码重用的目的。另外,子类除了重用父类的代码以外,还可以扩展自身的属性和方法,来描述子类特有的特征和行为。

例如:人类和马类这两个类,有什么共同的特征和行为呢?都有年龄,都要呼吸,都可以行动,都要吃奶。我们可以把人类和马类相同的特征和行为抽取出来,形成一个父类:哺乳动物。人类和马类只要继承哺乳动物这个父类。那么,就可以直接重用哺乳动物父类中定义的属性和行为,相同的属性和行为就可以不用再重复描述。所以,通过继承,可以达到代码很大的重用。

除此之外,人类和马类还可以再定义自己本身的特征和行为。比如,马要吃草,人可以说话。那么,人类和马类可以在继承了哺乳动物父类的同时,再定义说话或吃草的行为,来扩展自身的特征和行为。

使用继承有很多优点,父类的大部分功能可以通过继承关系自动进入子类;修改或扩展继承而来的属性和方法较为容易。那么,如何判断两个类之间是否有继承关系呢?很简单,用”是”来判断。比如:马是动物。那么马继承于动物。玫瑰是植物。那么玫瑰继承于植物。骂人的时候,我们会说:你是畜牲,那么这个人继承于畜牲,象畜牲一样没有人性。你是猪,那么这个人继承于猪,象猪一样愚笨。这就是所谓的”is-a”。

但是,继承同样有很多缺点。人类在大千世界中,不断的认识世界,也不断的改造世界。人类曾经梦想,在天空中飞翔。那么,人类如何飞行呢?鸟可以飞行,那是因为鸟有翅膀这个特征,才会拥有飞这个行为。如果人类继承于鸟类,象鸟一样长出翅膀,那么也就可以有飞行的行为了。

《封神榜》中的雷震子和天使,其实就是人类想在天空中飞行的一种想法。那就是继承鸟这个类,拥有鸟类的翅膀和飞行的行为。

那么,人类想下海应该怎么办呢?于是人类又在想,只要将人类继承于鱼类,拥有鱼的尾巴,那么就可以下海了。随着这种想法的产生,美人鱼就出现了。

那么,如果人类既想飞行,又想下海应该怎么办呢?有人说,那还不简单,把人类同时继承于鸟类和鱼类不就行了吗。但是,不好意思,在java中,类只能单根继承。也就是说,一个类只能有一个父类,不能同时继承两个父类。所以,从这里就可以看出继承的其中一个缺点:无法通过继承的方式,重用多个类中的代码。

除此之外,继承还有第二个缺点,那就是,父类的属性和方法,子类是无条件继承的。也就是说,不管子类愿意不愿意,都必须继承父类所有的属性和方法。比如,每个人都有自己父母,如果父母比较富有,那么子女就吃得好穿得好。如果父母是穷人,那么子女吃不饱穿不暖。很显然,所有的人都希望自己是富二代,官二代,而不想成为穷二代。不过,人是无法选择自己父母的。所以,父母的一切,自己是无条件接受的。

同样道理,如果人类继承于鸟类,我们希望拥有的是:鸟的翅膀和飞的行为。但是,鸟还有吃虫的行为,鸟还有下蛋的行为。这些是我们不希望拥有的。不过,如果人类继承于鸟类的话,那么吃虫和下蛋的行为,人类就得无条件接受了。所以,使用继承很容易造成方法的污染。一旦父类的属性和方法,在子类中不能完全适用。那么,也就不应该使用继承关系了。

还有,从父类继承而来的实现是静态的,不能在运行时发生改变,不够灵活。比如,有一个人从春熙路到天府广场去。

当我们调用run()方法时,就只能打印从父类中继承的run方法。如果这个人想骑单车去天府广场应该怎么办呢?有人说,简单,在CDMan中重写run()不就行了吗?

但是,如果这个人想骑单车走一段,再开汽车走一段,就没法通过继承和重写来实现了。所以,无论是从父类中继承的方法,还是子类重写的父类方法,实现的都是一种静态的复用。不能在运行时发生改变,灵活性比较差。

那么,如何解决继承的这些缺点呢?荀子在《劝学》中,有这样的一段话:”假舆马者,非利足也,而致千里;假舟楫者,非能水也,而绝江河。君子生非异也,善假于物也。”就是说,人可以骑马,即使这个人跑得不快,也可以到达千里之外。人可以坐船,即使这个人不会游泳,也可以到达江河的任何位置。君子其实没什么太多特别的地方,只不过善于利用工具而已。这就是所谓的”has-a”。拥有什么,或者使用什么。

荀子的这段话,指出了解决继承缺陷办法,那就是使用聚合/组合达到代码的复用。比如,人想上天怎么办呢?可以利用飞机上天。人想下海怎么办呢,可以利用轮船下海。并不要求人要长出翅膀,人要长出鱼尾。

这样的解决方案,其实就是告诉我们,与其我们”是什么”,倒不如我们”用什么”。也就是用聚合/组合复用,去代替继承复用。把一些特征和行为抽取出来,形成工具类。然后通过聚合/组合成为当前类的属性。再调用其中的属性和行为达到代码重用的目的。

换句话说,用”has-a”(有什么或用什么)去替代”is-a”(是什么)。

从以上代码可以看出,通过聚合/组合关系,可以解决继承的缺点。由于一个类可以建多个属性,也就是可以聚合多个类。所以,可以通过聚合/组合关系,重用多个类中的代码。

另外,我们可以选择一个类中是否应该具有某种行为,从而决定应该聚合那些类,不应该聚合那些类。这样,通过聚合/组合关系,也可以避免继承所带的方法污染问题。所以,使用聚合/组合,具有很强的代码重用性和灵活性。

聚合/组合复用也可以在运行时动态进行。新对象可以使用聚合/组合关系,将新的责任委派到合适的对象。

从这里可以看出,人类可以随时改换交通工具,达到行走的目的。这种方式可以在运行期间,随时改变接口属性的实现类。从而调用不同实现类描述的具体方法,灵活性很强。

总结:

继承和聚合/组合都可以达到代码重用的目的。继承有自身的优点,父类的大部分功能可以通过继承关系自动进入子类;修改或扩展继承而来的实现较为容易。

但是,继承同样有缺点,

无法通过继承达到多个类代码的重用。父类的方法子类无条件继承,很容易造成方法污染。从父类中继承的方法,是一种静态的复用。不能在运行时发生改变,不够灵活。继承可以用,但使用继承需要谨慎。一般来说,使用继承有两个条件:

父类中所有的属性和方法,在子类中都适用。子类不需要再去重用别的类中的代码。如果不能满足这两个条件,那么就应该使用聚合/组合关系去替代继承,来达到代码的复用。

java 组合优与继承_Java中为什么老鸟要告诉你优先使用组合而不是继承?相关推荐

  1. java的继承_java中的继承(一)

    在java中,所有的类都有一个默认的父类Object,即使我们没有显式的去继承这个类.在Object类中定义了一些方法,其中有几个方法是我们必须掌握的,比如equals方法,hashCode方法,wa ...

  2. java中所有的类都继承于_Java中所有的类都是通过直接或间接地继承( )类得到的...

    Java中所有的类都是通过直接或间接地继承( )类得到的 答:java.lang.Object 关于主机地址 192.168.19.125 (子网掩码: 255.255.255.248 ),以下说法正 ...

  3. 在java语法中继承_java中的继承

    一.继承: 1.如果不使用继承,会出现以下一些问题: (1)代码重复 (2)如果要修改的话,两个类都需要修改. 2.继承体现的是一种is a 的关系.eg:Dog is a Pet;apple is ...

  4. java 枚举不能继承_Java中的枚举类为何不能有public构造器

    从Java 5開始有了枚举类,须要注意的是enum定义的类默认继承的是java.lang.Enum类而不是Object类. 同一时候注意枚举类不能派生子类(类的默认修饰符为final).其原因基于它仅 ...

  5. java 数组对象属性数组_Java中数组的特性

    数组是基本上所有语言都会有的一种数据类型,它表示一组相同类型的数据的集合,具有固定的长度,并且在内存中占据连续的空间.在C,C++等语言中,数组的定义简洁清晰,而在java中确有一些会让人迷惑的特性. ...

  6. java implements 多个接口_JAVA中implements实现多接口

    JAVA中implements实现多接口 这里有一个游戏,人猿泰山. 主角是一个单独的类,这里我们主要用怪物说明接口的用法: 怪物有很多种, 按地域分:有的在天上飞,有的在地上跑,有的在水里游 按攻击 ...

  7. java(x ) 3的值_java中,设x=2,则表达式 (x++)*3的值是多少 设x=2则表达式(x+

    是6,如果是 ++x就是 9 原因 x++是先用原来的值运算 后赋值 ++x先给x自增,再运算 (x++)/3 x++的意思是先运算,后加1,也就是运算的时候x还是为2,运算过后x才会变成3. 而且 ...

  8. java 基本类型的引用_Java中的基本数据类型与引用数据类型

    一.基本数据类型 byte.short.int.long(整数类型) float.double(浮点数类型) char(字符型) boolean(布尔类型 ) Java数据大多数存放在堆栈中.栈区:存 ...

  9. java原始类型和引用类型_Java中的8种原始类型

    java原始类型和引用类型 几年前,当我开始编辑Java Basics系列时,我认为将一些非常详细的信息拉到自己的帖子中是很有意义的. 这样,初学者的内容就更容易消化了. 首先,我将介绍有关Java的 ...

最新文章

  1. python中进制_python中进制的算法
  2. mac 如何查看anaconda的路径_Mac OS如何直接查看gif图片?分享MAC直接查看gif图片的三种方法...
  3. 机器学习必备宝典-《统计学习方法》的python代码实现、电子书及课件
  4. git 怎么还原历史版本_4. Git--修改/回退等操作
  5. phpcmsV9发布文章后无法删除?后台找不到了?从phpmyadmin数据库删除吧!
  6. 【Kafka】kafka 再均衡监听器 ConsumerRebalanceListener
  7. 如何快速获取CSDN积分
  8. VS2015 自动代码补全
  9. 互联网大厂数据分析面试常见问题及解法,建议收藏
  10. JAVA系统蓝屏_Tomcat启动系统蓝屏
  11. 免证书发布ipa文件真机测试
  12. 用什么软件可以给照片加文字描述?
  13. MarkDown生成目录索引
  14. patch-package打补丁
  15. 05- 线性回归算法 (LinearRegression) (算法)
  16. DedeCMS找后台目录漏洞
  17. 物联网基础知识介绍及常见的几种无线通讯方式和应用
  18. ddz指标最佳数值_大单分差指标ddz如何解析资金流向与筹码分布
  19. C++编译调试问题(一)
  20. 确定账号登录和密码确认

热门文章

  1. 接手了一座年收入 2000 万美元的“屎山”,我到底该重写还是跳槽?
  2. Linux下以服务的方式部署springboot项目
  3. Cris 的 Scala 笔记(三):变量
  4. python tkinter canvas 画心形
  5. 越狱相关五:杂项记录
  6. 苹果电脑怎么删除旧账户_如何找到您不记得的旧在线帐户
  7. 【Stable Diffusion | AI 绘画】手把手教你体验--AI 生成唯美二次元
  8. 联想笔记本暗屏几乎看不见_联想笔记本屏幕突然变得很暗,基本看不见,怎么办,十万火急,是不是屏幕坏了???...
  9. python 匹配字符串开头和结尾
  10. 卸载和安装番茄小助手