21.面向对象特征——继承


一、概述

1、定义

  • 继承:就是子类继承父类的属性行为,使得子类对象具有父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

2、好处

  • 提高代码的复用性
  • 类与类之间产生了关系,是多态的前提

二、继承的格式

通过extends关键字,可以声明一个子类继承另一个父类,定义格式如下:

class 父类{
    ...
}

class 子类 extends 父类{
    ...
}

举例:

// 定义一个员工类(父类)
public class Employee {
    public void method(){
        System.out.println("方法执行!");
    }
}

// 定义一个教师类(子类)
// 定义了员工的子类:讲师
public class Teacher extends Employee{

}

// 定义一个测试类
public class Demo01Extends {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.method();

        Assistant assistant = new Assistant();
        assistant.method();
    }
}

三、继承后的特点——成员变量

当类之间产生了关系后,其中各类中的成员变量,会产生哪些影响?

1、成员变量不重名

如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:

public class Employee {
    // Employee中的成员变量
    int age = 20;
}

// 定义了员工的子类:讲师
public class Teacher extends Employee{
    int age_teacher = 35;
}

public class Demo02Extends {
    public static void main(String[] args) {
        // 创建父类对象
        Employee e = new Employee();
        System.out.println(e.age);

        // 创建子类对象
        Teacher teacher = new Teacher();
        System.out.println(teacher.age);
        System.out.println(teacher.age_teacher);
    }
}

2、成员变量重名

如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下:

public class Employee {
    // Employee中的成员变量
    int age = 20;

    public void method(){
        // 使用本类当中的age
        System.out.println(age);
    }
}

// 定义了员工的子类:讲师
public class Teacher extends Employee{
    int age = 35;

    public void method_teacher(){
        // 因为本类当有 age, 所有优先使用本类的age
        System.out.println(age);
    }
}

package cn.wolfwotz.day05.Demo02;

// 父类子类成员变量重名
public class Demo03Extends {
    public static void main(String[] args) {
        // 创建父类对象
        Employee e = new Employee();
        System.out.println(e.age);
        System.out.println("======");

        // 创建子类对象
        Teacher teacher = new Teacher();
        System.out.println(teacher.age);// 优先使用子类, 35(通过对象名.成员变量,'.'左边是谁就优先用谁,没有则向上找)
        System.out.println("======");

        // 这个方法是子类的,优先使用子类的,没有再向上找
        teacher.method_teacher(); // 35
        // 这个方法是定义在父类当中的(该方法属于谁,就用谁,没有则向上找)
        teacher.method();// 20
    }
}

(1)、访问成员变量时:

  • 直接通过子类对象访问成员变量
    • ‘.’左边是谁,就优先用谁,没有则向上找父类
  • 间接通过成员方法访问成员变量
    • 该方法属于谁,就优先用谁,没有则想上找

(2)、区分局部变量、子类成员变量、父类成员变量

变量 写法
局部变量 直接写成员变量(num)
子类成员变量 this.成员变量(this.num)
父类成员变量 super.成员变量(super.num)
public class Employee {
    // Employee中的成员变量
    int num = 10;

}

// 定义了员工的子类:讲师
public class Teacher extends Employee{
    int num = 20;

    public void method(){
        int num = 30;
        System.out.println(num); // 30, 局部变量
        System.out.println(this.num); // 20 子类成员变量
        System.out.println(super.num); // 10 父类成员变量
    }
}

package cn.wolfwotz.day05.Demo02;

public class Demo04Extends {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.method();
    }
}

四、继承后的特点——成员方法

当类之间产生了关系,其中各类的成员方法,又会产生哪些影响?

1、成员方法不重名

如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会现在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类不存在就会执行父类中相应的方法。

2、成员方法重名——重写(override)

如果子类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写(Override).

  • 方法重写:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也成为重写或者复写。声明不变,重新实现
public class SuperClass {
    public void show(){
        System.out.println("Superclass show");
    }
}

public class SubClass {
    // 子类重写父类方法
    public void show(){
        System.out.println("Subclass show");
    }
}

public class Demo05Extends {
    public static void main(String[] args) {
        // 创建子类对象
        SubClass sub = new SubClass();
        // 子类 show function
        sub.show(); // Subclass show
    }
}

3、重写的应用

子类可以根据需要,定义特定于自己的行为,既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行拓展增强。

例:新的手机增加来电显示头像功能:

public class Phone {
    public void sendMessage(){
        System.out.println("发短信");
    }

    public void call(){
        System.out.println("打电话");
    }

    public void showNum(){
        System.out.println("来电显示");
    }
}

public class NewPhone extends Phone{
    // 重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
    public void showNum(){
        // 调用父类已经存在的功能
        super.showNum();
        // 增加自己特有的显示功能
        System.out.println("显示来电姓名");
        System.out.println("显示头像");
    }
}

public class Demo06Extends {
    public static void main(String[] args) {
        // 创建子类对象
        NewPhone np = new NewPhone();

        // 调用父类继承而来的方法
        np.call();

        // 调用子类重写的方法
        np.showNum();
    }
}

这里重写时,用到super.父类成员方法,表示调用父类的成员方法

4、注意事项

  • 子类方法覆盖父类方法,必须要保证权限大于等于父类权限(小拓展:public > protected > (default) > private)

    备注:(default)不是关键字default,而是什么都不写

  • 子类方法覆盖父类方法,函数名和参数列表都要一模一样

  • 子类方法覆盖父类方法,子类方法的返回值必须小于等于父类方法的返回值范围

5、重写和重载的区别

  • 重写(override):方法的名称一样,参数列表【也一样】
  • 重载(overload):方法的名称一样,参数列表【不一样】

五、继承后的特点——构造方法

当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?

回忆构造方法的定义格式和作用:

  • 构造方法的名字必须与类名字一致。所以子类是无法继承父类构造方法的
  • 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super(),表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用
public class SuperClass {
    public SuperClass(){
        System.out.println("父类构造方法");
    }
}

public class SubClass extends SuperClass{
    public SubClass(){
//        super(); // 在调用父类无参构造,不写也会有,编译器赠送
        System.out.println("子类构造方法");
    }
}

public class Demo07Extends {
    public static void main(String[] args) {
        SubClass sub = new SubClass();
    }
}


输出结果:
父类构造方法
子类构造方法

1、特点

  • 子类构造方法当中有一个默认隐含的super()调用,所以一定是先调用的父类构造,后执行的子类构造
  • 子类构造可以通过super()关键字来调用父类重载构造
  • super的父类调用,必须是子类构造方法的第一个语句,不能一个子类构造多此super构造
  • 子类必须调用父类构造方法,不写则赠送super(),写了则用写的指定的super调用,super只能有一个,还必须第一个

六、继承的特点

  • Java只支持单继承,不支持多继承
// 一个类只能有一个父类,不可以有多个父类
class C extends A{}; // ok
class C extends A, B ... // error
  • Java 支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
  • 子类和父类是一种相对的概念

Author: Wolfwotz
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Wolfwotz !
  TOC