Java(50):Java继承与组合

     Java继承和组合,共同点:都可以实现代码的复用
     不同点:
is-a关系:使用继承
has-a关系:使用组合

       继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

      继承需要符合的关系是:is-a,父类更通用,子类更具体。

Java继承的特性

  • 子类拥有父类非 private 的属性、方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法。

  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。

  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

Java继承与组合

继承是实现类复用的重要手段,但继承带来了一个坏处:破坏封装
组合也是实现类复用的重要方式,而组合可以提供良好的封装性。

一、继承的规则

为了保证父类有良好的封装性,不会被子类随意修改,设计父类通常应该遵循以下规则

1、尽量隐藏父类的内部数据,尽量把父类的所有成员变量设置为 private 访问类型,不要让子类直接访问父类的成员变量;

2、不要让子类可以随意访问和修改父类方法,父类中仅为辅助其他工具的方法,应该使用private 访问控制符修饰,让子类无法访问该方法;如果父类中的方法需要被外部类调用,则必须设置为  public 修饰,但不希望子类重写该方法,可以使用final修饰符来修饰该方法;如果希望父类的某个方法被子类重写,但不希望被其他类自由访问,则可以使用protected来修饰该方法。

备注:如果不需要外部类调用,只需要子类调用,并且不希望子类重写,那么设置为:protected final 

3、尽量不要在父类构造器中调用将要被子类重写的方法。

在上类代码中:出现了空指针。

产生空指针异常的原因:当系统试图创建Sub对象时,同样会先执行其父类构造器,如果父类构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法,当创建Sub对象时,会先执行Base类中的Base构造器,而Base构造器中调用test()方法-----并不是1而是2,此时的Sub对象的name实例变量是null,因此将引发空指针异常。

到底何时需要从父类派生出新的子类,具备以下条件:

  • 子类需要额外增加属性,不仅仅是属性值的改变。 例如:从Person类派生出Student子类,Person类没有提供grade(年级)属性,而Student类需要grade属性来保存Student对象就读的年级,这种父类到子类的派生,就符合Java继承的前提。
  • 子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)。例如从Person类派生出Teacher类,其中Teacher类需要增加一个teaching()方法,该方法用于描述Teacher对象独有的行为方式,教学。

二、利用继承来实现复用

       在继承中,子类可以直接获得父类的public方法,程序使用子类时,将可以直接访问改子类从父类那里继承到的方法。
而组合则是把旧类对象作为新类对象的成员变量组合进来,用以实现新类的功能,用户看到的是新类的方法,而不能看到被组合对象的方法,因此,通常在新类中使用private修饰被组合的旧类对象。

假设有三个类:Animal、Wolf 和 Bird,他们之间有如下所示的继承树:

class Animal{
    private void beat()
    {
        System.out.println("心脏跳动。。。");
    }
    public void breath()
    {
        beat();
        System.out.println("吸一口气,吐一口气,呼吸中。。。");
    }
}
//继承父类Animal,直接复用breath()方法
class Bird extends Animal{
    public void fly()
    {
        System.out.println("i can fly.");
    }
}

//继承父类Animal,直接复用breath()方法
class Wolf extends Animal{
    public void run()
    {
        System.out.println("i can run.");
    }
}

public class inheritTest {
    public static void main(String [] args)
    {
        Bird b = new Bird();
        b.breath();
        b.fly();

        Wolf w=new Wolf();
        w.breath();
        w.run();
    }
}

继承执行结果:

三、利用组合实现复用

      如果需要服用一个类,除了把这个类当成基类来继承之外,还可以把该类当成另外一个类的组合成分,从而允许心累直接服用该类的public方法。不管是继承还是组合,都运行在新类(对于继承就是子类)中直接复用旧类(对于继承是父类)的方法。

复用:仅从类复用的角度来看,可以发现父类的功能等同于被组合的类,都将自身的方法提供给新类使用;子类和组合关系里的整体类,都可复原原有类的方法,用于实现自身的功能。

如果只是出于类复用的目的,并不一定需要使用继承,完全可以使用组合来实现。

class Animal{
    private void beat()
    {
        System.out.println("心脏跳动。。。");
    }
    public void breath()
    {
        beat();
        System.out.println("吸一口气,吐一口气,呼吸中。。。");
    }
}
class Bird{
    //将原来的父类组合到原来的子类,作为子类的一个组合成分。
    private Animal a;
    public Bird(Animal a)
    {
        this.a=a;
    }
    //重新定义一个自己的breath方法
    public void Breath()
    {
        //直接复用Animal提供的breath()方法来实现Bird的breath()方法。
        a.breath();
    }
    public void fly()
    {
        System.out.println("i can fly.");
    }
}

class Wolf{
    //将原来的父类组合到原来的子类,作为子类的一个组合成分。
    private Animal a;
    public Wolf(Animal a)
    {
        this.a=a;
    }
    //重新定义一个自己的breath方法
    public void Breath()
    {
        //直接复用Animal提供的breath()方法来实现Bird的breath()方法。
        a.breath();
    }
    public void run()
    {
        System.out.println("i can run.");
    }
}

public class CompositeTest {
    public static void main(String [] args)
    {
       //此时需要显性创建被组合的对象。
        Animal a1 = new Animal();
        Bird b = new Bird(a1);
        b.Breath();
        b.fly();
        //此时需要显性创建被组合的对象。
        Wolf c = new Wolf(a1);
        c.Breath();
        c.run();
    }
}

组合执行结果:

心脏跳动。。。
吸一口气,吐一口气,呼吸中。。。
i can fly.
心脏跳动。。。
吸一口气,吐一口气,呼吸中。。。
i can run.

总之继承要表达的是一种“是(is a)”的关系,而组合表达的是“有(has a)”的关系。

参考:Java继承与组合

https://blog.csdn.net/weixin_43819113/article/details/90273844

参考:Java 继承 | 菜鸟教程

https://www.runoob.com/java/java-inheritance.html

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宁宁可可

您的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值