• java中的继承


    1、为什么要有继承

    代码中创建的类,主要是为了抽象现实中的一些事物(包含属性和方法)
    有的时候客观事物之间就存在一些关联关系,那么在表示成类和对象的时候也会存在一定的关联
    例如, 设计一个类表示动物:

    // Animal.java
    public class Animal {
      public String name;
    
      public Animal(String name) {
        this.name = name;
      }
    
      public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
      }
    }
    
    // Cat.java
    class Cat {
      public String name;
    
      public Cat(String name) {
        this.name = name;
      }
    
      public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
      }
    }
    
    // Bird.java
    class Bird {
      public String name;
    
      public Bird(String name) {
        this.name = name;
      }
    
      public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
      }
    
      public void fly() {
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    这个代码我们发现其中存在了大量的冗余代码
    仔细分析,我们发现 Animal 和 Cat 以及 Bird 这几个类中存在一定的关联关系

    • 这三个类都具备一个相同的 eat 方法,而且行为是完全一样的
    • 这三个类都具备一个相同的 name 属性,而且意义是完全一样的
    • 从逻辑上讲,Cat 和 Bird 都是一种 Animal (is - a 语义)

    此时我们就可以让 Cat 和 Bird 分别继承 Animal 类,来达到代码重用的效果
    此时,Animal 这样被继承的类,我们称为 父类 、基类 或 超类,对于像 Cat 和 Bird 这样的类,我们称为 子类,派生类和现实中的儿子继承父亲的财产类似,子类也会继承父类的字段和方法,以达到代码重用的效果

    2、继承的语法规则及细节

    基本语法

    class 子类 extends 父类 {
    }

    1. Java当中是单继承,不能同时继承两个类及其以上的类。(C++支持多继承)
    2. 子类构造的同时,先要帮助父类进行构造。
    class Animal {
      public String name;
      public int age;
      public Animal(String name, int age) {
        this.name = name;
        this.age = age;
      }
    }
    
    class Cat extends Animal {
      public Cat(String name) {
        // 使用 super 显示的调用父类带有两个参数的的构造方法
        super(name);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果父类没有写构造函数,则子类也无序显示的调用父类的构造函数,例如:

    class Animal {
      public String name;
      public int age;
    }
    
    class Cat extends Animal {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因为父类会隐式的生成一个无参的构造函数,而子类会隐式的调用父类的构造函数。

    注意:super调用父类的构造方法时,只能放在第一行,否则会报错

    在这里插入图片描述

    继承的内存图:

    在这里插入图片描述

    在这里插入图片描述

    当子类和父类中有同名的字段,优先使用子类的,如果想要使用父类字段,则需要使用super关键字,例如:

    没有使用super:
    在这里插入图片描述
    使用super:
    在这里插入图片描述

    3、protected 关键字

    如果把字段设为 private,子类不能访问。但是设成 public,又违背了我们 “封装” 的初衷
    所以应该使用protected关键字

    • 对于类的调用者来说, protected 修饰的字段和方法是不能访问的
    • 对于类的子类和同一个包的其他类来说,protected 修饰的字段和方法是可以访问的

    在父类中使用private:

    class Animal {
      public String name;
      public int age;
      private String sex;
      public Animal(String name, int age) {
        this.name = name;
        this.age = age;
      }
    }
    
    class Bird extends Animal {
      String wing;
      String name;
      public Bird(String name, int age, String wing) {
        super(name, age);
        this.wing = wing;
      }
      public void fly() {
        System.out.println(super.name + wing);
      }
    
      public void PrintSex() {
        System.out.println(super.sex);
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    在父类中使用protected:
    在这里插入图片描述
    在这里插入图片描述

    Java 中对于字段和方法共有四种访问权限

    1. private: 类内部能访问, 类外部不能访问
    2. 默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
    3. protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
    4. public : 类内部和类的调用者都能访问

    在这里插入图片描述

    4、更复杂的继承关系

    在生或中,类与类之前可能存在非常复杂的关系,例如:
    在这里插入图片描述
    这个时候使用继承方式来表示,就会涉及到更复杂的体系

    // Animal.java 
    public Animal { 
     ... 
    } 
    // Cat.java 
    public Cat extends Animal { 
     ... 
    } 
    // ChineseGardenCat.java 
    public ChineseGardenCat extends Cat { 
     ... 
    } 
    // OrangeCat.java 
    public Orange extends ChineseGardenCat { 
     ... 
    } 
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如刚才这样的继承方式称为多层继承,即子类还可以进一步的再派生出新的子类

    时刻牢记,我们写的类是现实事物的抽象。而我们真正在公司中所遇到的项目往往业务比较复杂,可能会涉及到一系列复杂的概念,都需要我们使用代码来表示, 所以我们真实项目中所写的类也会有很多。 类之间的关系也会更加复杂。

    但是即使如此,我们并不希望类之间的继承层次太复杂。一般我们不希望出现超过三层的继承关系。如果继承层次太多,就需要考虑对代码进行重构了。

    如果想从语法上进行限制继承,就可以使用 final 关键字

    5、final关键字

    final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改)

    final 关键字也能修饰类,此时表示被修饰的类就不能被继承

    在这里插入图片描述

    final 关键字的功能是限制类被继承

    “限制” 这件事情意味着 “不灵活”。在编程中,灵活往往不见得是一件好事。灵活可能意味着更容易出错
    使用 final 修饰的类被继承的时候,就会编译报错,此时就可以提示我们这样的继承是有悖这个类设计的初衷的

    平时使用的 String 字符串类,就是用 final 修饰的,不能被继承
    在这里插入图片描述

    6、组合

    和继承类似,组合也是一种表达类之间关系的方式,也是能够达到代码重用的效果
    例如表示一个学校:

    public class Student { 
     ... 
    } 
    public class Teacher { 
     ... 
    } 
    public class School { 
     public Student[] students; 
     public Teacher[] teachers; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    组合并没有涉及到特殊的语法(诸如 extends 这样的关键字),仅仅是将一个类的实例作为另外一个类的字段。这是我们设计类的一种常用方式之一。

    组合表示 has - a 语义
    在刚才的例子中,我们可以理解成一个学校中 “包含” 若干学生和教师

    继承表示 is - a 语义
    在上面的 “动物和猫” 的例子中,我们可以理解成一只猫也 “是” 一种动物

  • 相关阅读:
    LVGL8.3.6 Flex(弹性布局)
    Avoiding Row-by-Row Processing 避免逐行处理
    【分析BMI指数~python】
    自考重庆工商大学难不难?
    【714. 买卖股票的最佳时机含手续费】
    Chapter 5 决策树和随机森林实践
    思科华为设备DHCP配置命令对比
    MySql 数据库【约束】
    go template函数,变量等语法示例
    #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • 原文地址:https://blog.csdn.net/qq_56044032/article/details/127658369