01-继承

一、引入

相同特征产生代码冗余,有如下俩个类(Java学生类和UI学生类)

// JavaStudent.java
public class JavaStudent {
    private String number;   // 学号
    private String name;   // 姓名
    private int age;   // 年龄
    private String classes;   // 班级
    private String project;   // 项目

    // 考试
    public void exam(){
        System.out.println("学员考试");
    }

    // 登录
    public boolean login(String stuNo, String pwd){
        System.out.println("使用学号和密码登录");
        return true;
    }

    //...
}

// UIStudent.java 
public class UIStudent {
    private String number;   // 学号
    private String name;   // 姓名
    private int age;   // 年龄
    private String classes;   // 班级
    private String opus;   // 作品

    // 考试
    public void exam(){
        System.out.println("学员考试");
    }

    // 登录
    public boolean login(String stuNo, String pwd){
        System.out.println("使用学号和密码登录");
        return true;
    }

    //...
}

经过观察俩个类可以发现,它们都有一些相同特征(相同的属性、相同的方法),比如相同的属性有学号、姓名、年龄、班级;相同的方法有考试和登录。

针对上述发现问题,就有如下解决方案,就是把相同的属性和行为抽取出来,就可以降低重复代码的书写。抽取出来的共性代码单独封装到一个类中

二、概述

  1. 继承是将多个类的相同属性和行为抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的这个类即可使用这些属性和行为
  2. 多个称为子类(派生类),单独的这个类称为父类(基类、超类)

三、使用方式

当多个类中有相同的代码(属性、行为)时,把相同的代码抽取出来,封装到了一个单独的类中,这样做的好处就是提高代码的复用性,但是这样做就面临一个问题,就是单独封装出来的类和之前被抽取代码的类,怎么建立联系(允许使用单独封装类中的成员)。接下来就解决这个问题

  • 使用继承需要在2个或者多个类之间

  • Java使用关键字extends表示继承

  • 语法格式

    public class 子类名 extends 父类名{
        
    }
    
  • 原则

    在类与类之间建立继承关系时,必须符合 is a(是一个...)

    要符合现实生活中的认知

    比如

    • Java学生是一个学生
    • 猫是一个动物
    • 冰箱是一个电器

    如果是如下就不符合了

    • Java学生是一个电器

四、使用继承改造代码

新增一个Student类,把JavaStudent类和UIStudent类中的相同特征进行抽取,如下

Student.java

// Student.java
public class Student {
    private String number;   // 学号
    private String name;   // 姓名
    private int age;   // 年龄
    private String classes;   // 班级

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    // ...(其他属性get、set方法;Student空参构造方法、有参构造方法)

    // 考试
    public void exam(){
        System.out.println("考试");
    }

    // 登录
    public boolean login(String stuNo, String pwd){
        System.out.println("登录");
        return true;
    }
}

JavaStudent.java

public class JavaStudent extends Student{
    private String project;   // 项目
    //...(project属性get、set方法、JavaStudent空参构造方法、有参构造方法)
}

UIStudent.java

public class UIStudent extends Student{
    private String opus;   // 作品
  //...(opts属性get、set方法、UIStudent空参构造方法、有参构造方法)
}

上述代码JavaStudent类和UIStudent类就继承了Student类,抽取完相同特征后,JavaStudent类和UIStudent类只保留了一些特有的特征,子类就可以访问父类的非私有成员。虽然此时JavaStudent类和UIStudent类不能直接访问父类的私有属性,但可以通过getset方法进行访问,建立一个测试类验证

public class Test {
    public static void main(String[] args) {
        JavaStudent javaStu = new JavaStudent("阿里云盘");
        javaStu.setNumber("10010");
        javaStu.setName("张三");
        javaStu.setAge(27);
        javaStu.setClasses("302");

        System.out.println(javaStu.getName() + "---" + javaStu.getProject());   // 张三---阿里云盘
        javaStu.exam();   // 使用父类的方法打印——考试
    }
}

五、使用规范

工作中对于继承应该遵循如下规范

  1. 多个类相同特征(共性属性、共性方法)放在父类中定义
  2. 子类扩展的属性和方法应该定义在本子类中

六、父子类的对比

  1. 子类和父类相比,子类的功能更强大
  2. 子类和父类相比,父类的范围表示更广

七、继承后子类对象的内存原理

基于上述代码,当你在测试类Test.javanew一个子类JavaStudent.java的时候,系统就会在堆内存中开辟一块新的空间,这个空间就属于javaStu这个对象,此时,这个空间一分为二,一块叫做父类成员空间super,一块叫做子类成员空间this,当我们使用考试方法时javaStu.exam(),会首先进入子类成员空间进行查找,结果是没有找到,接着会进入父类成员空间查找,结果找到了,就调用

总结如下:

子类对象在创建时,在堆内存中开辟的空间包含了两部分内容

  • super空间:存储父类的相关成员
  • this空间:存储了子类自身的相关成员

子类对象在访问成员时:

  • 优先使用子类自己的成员,当子类没有该成员时,去super空间中使用父类的成员,如果父类也没有,会一直向上查找,如果直至Object类都没有的话,会报错。

八、特点

  1. 单继承,只支持单继承,不支持多继承
  2. 一个父类可以有多个子类
  3. 多层继承,子类C继承父类B,父类B可以继承父类A,如果一个类没有直接继承关系,默认继承Object,因此,所有类都是Object类的子类

九、访问特点

  • 变量访问

    在子类方法中访问一个变量,满足就近原则

    1. 先子类局部范围找
    2. 然后子类成员范围找
    3. 然后父类成员范围找,如果父类范围内还没有找到则报错
    4. 父类中私有的成员子类不能直接访问

    如果局部变量、本类成员变量、父类成员变量重名,应该按照如下进行区分

    1. 局部变量直接访问
    2. 本类成员变量,使用this访问
    3. 父类成员变量,使用super访问
    4. 使用this访问时,如果子类没有找到,也会去父类进行查找
  • 方法访问

    通过子类对象访问一个方法也满足就近原则

    1. 子类成员范围找
    2. 父类成员范围找
    3. 不能直接访问父类中私有成员

    如果父类中出现同名参数的访问,先优先使用子类的,要访问父类相同方法可以使用super关键字

posted @ 2023-07-11 17:19  徐林俊  阅读(3)  评论(0编辑  收藏  举报