在java中,有两种主要复用代码的方法:继承和组合。

继承,是OOP的一大特性,想必大家都非常熟悉了;组合,其实也很常见,只是不知道它的名字罢了。

继承

子类拥有父类的基本特性,需使用extend关键字实现,声明某子类继承于某父类

如下例子,麻雀继承鸟类

//鸟类
public class Bird {
public void eat(){
System.out.println("Bird eat");
}
public void fly(){
System.out.println("Bird fly");
}
}
//麻雀
public class Sparrow extends Bird{
public static void main(String[] args){
Sparrow sparrow = new Sparrow();
sparrow.eat();
sparrow.fly();
}
}

优缺点

优点
  • 子类能自动继承父类的接口

  • 创建子类的对象时,无须创建父类的对象

缺点
  • 破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性

  • 支持扩展,但是往往以增加系统结构的复杂度为代价

  • 不支持动态继承。在运行时,子类无法选择不同的父类

  • 紧耦合

缺点分析

1.为什么说破坏封装性?

封装是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部的信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

如下例子中父类Fruit中有成员变量weight。Apple继承了Fruit之后,Apple可直接操作Fruit类的成员变量,因此破坏了封装性!

public class Fruit {
//成员变量
public double weight;
public void info(){
System.out.println("我是一个水果!重" + weight + "g!");
}
} public class Apple extends Fruit {
public static void main(String[] args){
Apple a = new Apple();
a.weight = 10;
a.info();
}

2.子类对父类的扩展往往会增加系统结构复杂度,继承树深度加深,结构越复杂

3.继承不能支持动态继承

因为继承是编译期就决定下来的,无法在运行时改变

4.为什么说紧耦合?

意思是父类和子类的耦合性很高,比如说将父类的一个成员变量名称修改了,子类用到这个变量的地方就需要做修改。

做为一个设计者,应当努力减小耦合关系。

组合

组合通常用于想在新类中使用现有类的功能,而非它的接口。

可能对于名字很陌生,但是用法很熟悉,看下面例子

//鸟类
public class Bird {
public void eat(){
System.out.println("Bird eat");
}
public void fly(){
System.out.println("Bird fly");
}
}
//麻雀
public class Sparrow {
private Bird bird = new Bird (); public void eat(){
bird.eat();
} public void fly(){
bird.fly();
} public void walk(){
System.out.print("Sparrow walk");
} public static void main(String[] args){
Sparrow sparrow = new Sparrow();
sparrow.eat();
sparrow.fly();
sparrow.walk();
}
}

优缺点

优点
  • 不破坏封装,整体类与局部类之间松耦合,彼此相对独立

  • 具有较好的可扩展性

  • 支持动态组合。在运行时,整体对象可以选择不同类型的局部对象

  • 整体类可以对局部类进行包装,封装局部类的接口,提供新的接口

缺点
  • 整体类不能自动获得和局部类同样的接口

  • 创建整体类的对象时,需要创建所有局部类的对象

继承与组合对比

相对于组合,继承的优点:

1、在继承中,子类自动继承父类的非私有成员,在需要时,可选择直接使用或重写。

2、在继承中,创建子类对象时,无需创建父类对象,因为系统会自动完成;而在组合中,创建组合类的对象时,通常需要创建其所使用的所有类的对象。

相对于集成,组合的优点:

1、在组合中,组合类与调用类之间低耦合;而在继承中子类与父类高耦合。

2、可动态组合。

如何选择

从前面的介绍已经优缺点对比中也可以看出,组合确实比继承更加灵活,也更有助于代码维护。

所以,建议在同样可行的情况下,优先使用组合而不是继承。因为组合更安全,更简单,更灵活,更高效。

面向对象中有一个比较重要的原则『多用组合、少用继承』或者说『组合优于继承』,这也是六大设计原则之一的合成复用原则。

那我们该如何判断是否应该使用继承呢?在java编程思想中提供了一个简单的判断方法,问一下自己“真的需要向上转型吗?”。

如果是必须的,则继承是必要的。反之则应该好好考虑是否需要继承。

扩展:向上转型

即用父类引用指向子类对象

什么时候用到向上转型?

方法调用需要同时接受两个子类的类型,这时就需要将他们的父类作为方法参数,使用向上转型将子类转换为父类类型

以上文中继承的例子Fruit和Apple,添加Banner类和一个测试类,如下

   public class Bananer extends Fruit {

   }

   public class Test{
public static void main(String[] args){
Fruit a = new Apple();//向上转型
Fruit b = new Bananer ();//向上转型
getWight(new Apple());//传入子类,自动向上转型
getWight(new Bananer ());//传入子类,自动向上转型
} public void getWight(Fruit f){
System.out.println(f.wight)
}
}

ANDKS

  • End -

一个立志成大腿而每天努力奋斗的年轻人

伴学习伴成长,成长之路你并不孤单!

java小心机(4)| 继承与组合的爱恨情仇的更多相关文章

  1. java小心机(5)| 浅谈类成员初始化顺序

    类成员什么时候会被初始化呢?一般来说:"类的代码在初次使用时才被加载",加载过程包括了初始化. 比如说new A()调用构造函数时,类中全部成员都会被初始化. 但对于static域 ...

  2. java小心机(3)| 浅析finalize()

    每天进步一丢丢,连接梦与想 如果你停止就是谷底,如果你还在努力就是上坡 系列文章 java"小心机"(1)[资源彩蛋!] java小心机(2)| 重载和构造器的小细节 预备知识 J ...

  3. java小心机(2)| 重载和构造器的小细节

    每天进步一点点,距离大腿又近一步! 阅读本文大概需要10分钟 java小心机,为你诉说java鲜为人知的一面 涉及基本数据类型的重载 基本类型能从一个"较小"的类型自动提升到&qu ...

  4. java"小心机"(1)【资源彩蛋!】

    每天进步一点点,距离大腿又近一步! 阅读本文大概需要9分钟 java"小心机"系列文章在此开篇.在这,将会给你带来曾经错过.忽略或感到模糊的知识,也许它很基础,微不足道,但它能修复 ...

  5. 又一次认识java(四) — 组合、聚合与继承的爱恨情仇

    有人学了继承,认为他是面向对象特点之中的一个,就在全部能用到继承的地方使用继承,而不考虑到底该不该使用,无疑.这是错误的.那么.到底该怎样使用继承呢? java中类与类之间的关系 大部分的刚開始学习的 ...

  6. java代码复用(继承,组合以及代理)

    作为一门面向对象开发的语言,代码复用是java引人注意的功能之一.java代码的复用有继承,组合以及代理三种具体的表现形式,下面一一道来. 第一种方式是通过按照现有的类的类型创建新类的方式实现代码的复 ...

  7. Java面试题之继承、组合、聚合有什么区别

    继承:他是is-a的关系,指一个类继承另外一个类的功能 例如:public class A extends B { } 聚合:他是has-a 例如:public class A{ List<B& ...

  8. java小心机(6)| 多态的一些坑

    对于"多态"的概念,想必大家都很熟悉了,但我们还是来回顾一下吧 class Actor { public void act(){ System.out.println(" ...

  9. Java豆瓣电影爬虫——模拟登录的前世今生与验证码的爱恨情仇

    前言 并不是所有的网站都能够敞开心扉让你看个透彻,它们总要给你出些难题让你觉得有些东西是来之不易的,往往,这也更加激发你的激情和斗志! 从<为了媳妇的一张号,我与百度医生杠上了>里就有网友 ...

随机推荐

  1. jquery核心基础

    jquery对对象的操作:   检查对象类型: 老式的javascript使用typeOf()操作符,但他是不符合逻辑的,在某些情况下,typeOf()返回的不是一个正确的值,或者返回一个出乎意料的值 ...

  2. C# Thread.Join();Thread.Abort();

    Join() 等待当前线程运行完成后,才继续执行主线程后续代码: Abort() 结束当前线程,继续执行主线程后续代码: Thread.Join(); static void Main(string[ ...

  3. CF Round #580(div2)题解报告

    CF Round #580(div2)题解报告 T1 T2 水题,不管 T3 构造题,证明大约感性理解一下 我们想既然存在解 \(|a[n + i] - a[i]| = 1\) 这是必须要满足的 既然 ...

  4. Vue的数据双向绑定和Object.defineProperty()

    Vue是前端三大框架之一,也被很多人指责抄袭,说他的两个核心功能,一个数据双向绑定,一个组件化分别抄袭angular的数据双向绑定和react的组件化思想,咱们今天就不谈这种大是大非,当然我也没到达那 ...

  5. 019.MFC_两种对话框

    对话框分为模态和非模态对话框两种 模态对话框(Modal) d.DoModal() 必须关闭才能返回主窗口 非模态对话框(Modaless) p->Create(IDD_DIALOG,this) ...

  6. 支撑百万级并发,Netty如何实现高性能内存管理

    Netty作为一款高性能网络应用程序框架,实现了一套高性能内存管理机制 通过学习其中的实现原理.算法.并发设计,有利于我们写出更优雅.更高性能的代码:当使用Netty时碰到内存方面的问题时,也可以更高 ...

  7. Python学习3月5号【python编程 从入门到实践】---》笔记(2)

    1.操作列表 一.遍历整个列表,并且想对每一个元素执行相同的操作.##这里就不得不提起我们一直用的For函数了. 二.深入地研究循环 (1)for  i  in superheroes:##首先读取其 ...

  8. $Poj2956/AcWing116\ The\ Pilots\ Brothers'Refrigerator$ 二进制

    AcWing $Sol$ 假设改变$[x1,y1]$和$[x2,y2]$的状态就可以达到目的.注意到先改变谁对结果是没有影响的!! 所以就可以直接枚举改变状态的结点而不需要注意顺序. $4*4$的矩阵 ...

  9. $CF24D\ Broken Robot\ DP+$高斯消元

    Luogu Description 你收到的礼物是一个非常聪明的机器人,行走在一块长方形的木板上.不幸的是,你知道它是坏的,表现得相当奇怪(随机).该板由n行和m列的单元格组成.机器人最初是在i行和j ...

  10. acwing 1250. 格子游戏 并查集

    地址 https://www.acwing.com/problem/content/1252/ Alice和Bob玩了一个古老的游戏:首先画一个 n×nn×n 的点阵(下图 n=3n=3 ). 接着, ...