【Java】面向对象特性之一:继承性 extends

137 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

1️⃣前言

大家好,我是翼同学。今天笔记的内容是:

  • 类的继承

2️⃣内容

2.1、概述

在面向对象的程序设计中,继承是一个重要的概念。继承允许我们创建有等级层次的类。

当一个类是从父类继承而来的,就意味着这两个类存在了is-a关系。is-a关系是继承的一个特征。

具体来说,继承就是子类可以继承父类的特征和行为,这样使得子类可以拥有父类的属性和方法。

比如说老虎类和狮子类都可以继承与哺乳动物类,使得子类具有父类的相同特征,同时又可以定义自己的特征。

2.2、extends关键字

在Java中,我们使用extends关键字来表明一个;类是从另一个类继承而来的。

举个例子:

下面的代码表示Manager类继承于Employee类:

class Manager extends Employee{
    // 添加一些属性和方法
    ...
}

事实上Java定义继承的方式和C++的很像,只不过Java通过关键字extends代替了C++中的冒号:。另外,Java中没有私有继承和保护继承,所有的继承都是公有继承。

2.3、父类和子类

关键字extends表明了此时创建的类继承于(或者说派生于)已存在的类。

我们将这个已存在的类称为父类、超类或者基类。新创建的类称为子类、派生类或者孩子类。

事实上,子类封装的数据会更多,功能也比父类丰富。因此我们说,父类更加通用,子类更加具体。我们会将通用的方法放在父类中,而具有特殊功能的方法放在子类中。

子类可以调用父类中的方法,因为子类自动继承了父类中的方法和属性。当我们在子类定义新的方法时,子类的对象可以调用,但父类的对象却无法使用;并且需要注意,子类不能删除父类中的任何属性或方法。

2.4、super关键字

举个例子:现在我们有一个Employee父类的部分代码如下:

class Employee{
    // 属性
    private double salary;
    // 方法
    public double getSalary(){
        return salary;
    }
}

此时定义一个子类Manager的部分代码如下:

class Manager extends Employee{
    // 属性
    private double bonus;
}

我们在Manager类中新定义了一个属性bonus,此时就需要重新编写一个getSalary()方法来覆盖父类中的方法。

class Manager extends Employee{
    // 属性
    private double bonus;
    // 方法
    public double getSalary(){
        return salary + bonus;
    }
}

但是,上面的代码无法运行。这是因为子类的对象无法访问父类中的私有属性。只有父类中的方法才能访问父类的私有属性,这一点需要注意。

但是,如果我们借助父类的公有方法来调用父类的属性,是否能成功呢?

class Manager extends Employee{
    public double getSalary(){
        double mySalary = getSalary();
        return mySalary;
    }
}

很遗憾,上述的代码仍然无法运行:子类在调用getSalary()方法时会导致无限次的调用自己,因为子类也有一个getSalary()方法,但我们希望调用的是父类中的getSalary()方法,因此运行后程序就会崩溃。

为了解决这种问题,我们可以使用关键字super

下面是子类中getSalary()方法的正确写法:

class Manager extends Employee{
    public double getSalary(){
       double mySalary = super.getSalary();
        return mySalary;
    }
}

简单来说,super关键字不是一个对象的引用,而是用于指示编译器调用父类方法的特有关键字,有点像C++中用::操作符来访问父类中的方法。

另外,super关键字在构造器方面的应用也很多。

比如说我们现在有一个父类MyBase,他的构造器如下所示:

public MyBase(int i, String s){
    data = i;
    str = s;
}

然后有一个子类MySon继承于父类MyBase,子类有一个新定义的属性ch,则子类的构造器可以这么写:

public MySon(int i, String s, char c){
    super(i, s);
    ch = c;
}

语句super(i, s);是调用父类构造器的简写形式。

由于子类的构造器无法访问父类的私有属性,因此必须利用父类的构造器来初始化父类的私有属性,也就是在子类中利用super关键字来实现对父类构造器的使用。

如果子类没有显示地调用父类的构造器,则会自动调用父类默认的无参构造器。但注意,如果父类没有无参构造器,并且子类又没有调用父类的其他构造器,此时Java编译器会报错。

2.5、多重继承

在继承机制方面与C++相比,Java是不支持多继承,这与C++不同。但是Java支持多重继承。

怎么理解呢?

下面代码属于多重继承,Java是支持的:

// C类继承于B类,而B类又继承于A类
class A {}
class B extends A {}
class C extends B {}

而多继承对于Java来说是不支持的,比如:

// C类想继承于A类和B类,这是错误的
class A {}
class A {}
class C extends A,B {}

另外,如果是不同子类继承于同一个父类的话,Java是支持的。

比如:

class A {}
class B extends A {}
class C extends A {}

2.6、小结

继承是java面向对象编程技术的一块基石,继承机制允许我们创建分等级层次的类。 对于继承:

  • 子类可以拥有父类的非private的属性和方法;
  • 子类可以定义自己的属性和方法,即丰富父类,进行一定的扩展;
  • 子类可以重写父类的方法;
  • Java的继承属于单继承,不支持多继承,但是可以多重继承;

3️⃣写在最后

好了,今天的笔记就记到这里。