前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java小心机(4)| 继承与组合的爱恨情仇

java小心机(4)| 继承与组合的爱恨情仇

作者头像
KEN DO EVERTHING
发布2019-01-17 16:43:40
5000
发布2019-01-17 16:43:40
举报
文章被收录于专栏:KEN DO EVERTHING

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

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

继承

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

代码语言:javascript
复制
//鸟类
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类的成员变量,因此破坏了封装性!

代码语言:javascript
复制
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.为什么说紧耦合? 意思是父类和子类的耦合性很高,比如说将父类的一个成员变量名称修改了,子类用到这个变量的地方就需要做修改。 做为一个设计者,应当努力减小耦合关系。

组合

组合通常用于想在新类中使用现有类的功能,而非它的接口。 可能对于名字很陌生,但是用法很熟悉,看下面例子

代码语言:javascript
复制
//鸟类
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类和一个测试类,如下

代码语言:javascript
复制
   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)
    }
  }

THANDKS

- End -

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java从心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 继承
    • 优缺点
      • 优点
      • 缺点
    • 缺点分析
    • 组合
      • 优缺点
        • 优点
        • 缺点
    • 继承与组合对比
      • 相对于组合,继承的优点:
        • 相对于集成,组合的优点:
        • 如何选择
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档