Java基础--继承

本文部分内容摘自:https://www.runoob.com/java/java-inheritance.html

什么是继承

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

例如人属于哺乳动物,鸡属于卵生动物,草属于植物,而哺乳动物、卵生动物、植物都属于生物。我们可以通过一张图来了解他们的继承结构:

通过图我们可以很清晰的看出,生物是哺乳动物的父类,哺乳动物是人的父类,鸡、草同理。

继承需要的关系是is-a的关系,以上图为例,人 is a 哺乳动物,哺乳动物 is a 生物。当满足这种is-a关系时便可以使用继承。像草is a 哺乳动物这一不成立的语句就不可以使用继承。

为什么要使用继承

使用继承的原因在于子类具有父类一些相同的特征(属性)和行为(方法)时,又与父类有一定的差异。在实际开发过程中,如果不使用继承,两个类之间容易有大量的代码重复,代码维护性不高。继承提取了两个类中共有的部分作为父类,通过继承的方式,子类不需要再重复写这部分共有的代码,只需要进行修改即可。

类的继承格式

Java中可以通过extends关键字申明一个类继承另一个类,一般形式如下:

class 父类{
    //父类的属性和方法
}

class 子类 extends 父类{
    //子类的属性和方法
}

Java除了继承类还有继承接口,我们可以使用implements关键字声明一个类继承一个接口,一般形式如下:

interface 接口A{
    //接口中的方法
}

class 类B implements 接口A{
    //重写接口中的方法
}

继承类型

还要注意,Java支持接口的多继承,但不支持类的多继承,原因是当两个父类具有相同的方法时,子类不知道需要调用哪一个方法。因此Java不支持多继承,但是Java支持多重继承。

继承的特性

  • 子类拥有非private的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
  • 子类可以用自己的方式实现父类,即重写父类的方法
  • Java是单继承,但可以多重继承。(这里主要讲的是类继承,接口支持多继承)
  • 继承提高了类的耦合性(继承的缺点,耦合性越高代码独立性越差)。

super和this关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来应用当前对象的父类。

this关键字:指向当前类的引用。

实例:

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

继承的注意事项

  1. final关键字声明的类是不能继承的,若声明方法,则该方法无法被子类重写。变量也是如此。
  2. 子类是不继承父类的构造器的,它只是调用(隐式或者显示)。如果父类的构造器带有参数,则必须在子类的构造器中显示地通过super关键字来调用父类的构造器并配以适当的参数列表。若没有参数则不需要使用super调用父类构造器,系统会自动调用父类的无参构造器。

继承和组合

说到继承就必须要说到组合。类继承和对象组合是实现类复用的两种最常见的技术。

继承上边已经介绍过了,在此讲一下继承的缺点:

  1. 父类的内部细节对子类是可见的。
  2. 子类从父类继承的方法在编译时就确定下来,所以无法在运行期间改变从父类继承的方法的行为。
  3. 子类和父类是一种高耦合,违背了java的设计原则。(设计原则之后会在另一篇博客详细讲述)
  4. 继承最大的弱点是打破了封装,子类与父类高度耦合,子类缺乏独立性,从而影响了子类的可维护性。
  5. 不支持动态继承,在运行时子类无法选择不同的父类。

组合

上边讲过继承是is a的关系,而组合的关系可以用has a 来表示。话不多说,看看代码就懂了:

​
class Animal {
  void eat() {
    System.out.println("吃东西中");
  }
}
 
class Dog  {
  private Animal a;
  public Dog(Animal a){
    this.a = a;
  }

  void eat() {
    System.out.println("dog");
    a.eat();
  }
  
  void fake(){
    System.out.println("汪汪汪");    
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    Dog d = new Dog(a);
    d.eat();
    d.fake();
  }
}

​

从上面代码可以清晰的看出,组合极大的降低了父类和子类的耦合性。组合简单来说就是通过拼装对象来实现类的复用,与继承相比,它更强调一个has a 的关系。

组合的优点:

  1. 不破坏封装,整体类和局部类之间松耦合,彼此相互独立。
  2. 具有较好的可扩展性。
  3. 支持动态组合,在运行时整体对象可以选择不同类型的局部对象。

组合的缺点:

  1. 创建整体类时,需要创建所有局部类对象,导致系统中对象的数量很多。
  2. 整体类不能自动获得和局部类同样的接口。

组合与继承的选择

既然组合能实现继承的作用,我们应该抛弃继承选择组合吗?答案是否定的,我们可以通过以下几点来决定选择组合还是继承:

  • 两个类之间明显存在整体和部分的关系,则应该使用组合来实现复用,当我们需要对已有类做一番改造,从而得到新的符合需求的类,则应该使用继承。
  • 当需要被复用的类一定不会改变时,应该使用组合,否则应该使用继承。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值