• Java教程之面向对象 - 继承


    前言 :

    Hello , 各位同学朋友大家好啊, 今天给大家分享的技术呢, 是面向对象三大特征之一的继承 .

    我们今天主要按照以下几个点, 展开继承的讲解

    目录 :

    • 继承的介绍

    • 继承的好处和弊端

    • 继承中成员访问特点 - 成员变量

    • 继承中成员访问特点 - 成员方法

    • 方法重写

    • 继承中成员访问特点 - 构造方法

    • this 和 super 关键字

    1. 继承的介绍

    提到了继承, 大家想到了什么 ? 是的, 子女继承到的家产, 那家产是存在着一种关系的, 父亲和儿子的关系

    对比生活中的继承, Java 中的继承, 其实就是让类与类之间产生关系, 什么关系 ? 子父类关系, 当这种关系建立起来之后, 子类就可以直接使用父类中, 非私有的成员了.

    聊到这个地方, 很多同学就在想, 我为什么让我的类与类之间建立这种关系呢 ? 请同学们先阅读下方代码

    假设, 我要编写一款 xxx 公司的人员管理系统, 这款管理系统需要对项目经理和程序员的信息做管理, 所以就需要编写如下两个类

    在这里插入图片描述

    现在大家可以发现, 这两个类中的东西, 完全是长一样的 !!! 那我将来要是再多一个 Hr 的类, 对人事的信息做管理, 这些重复的代码, 岂不是要再写一遍 ? 麻烦 !

    所以, 这时候我要用继承来优化代码了

    我将这些类当中, [共性] 或者说是 [相同] 的内容, 抽取到一个父类 (Employee 员工 ) 当中 , 再让 Coder 和 Manager 继承 Employee, 代码就不需要重复编写了 , 这就能够提高代码的复用性了 ~

    在这里插入图片描述

    ​ 但是, 代码层面, 我给如何让 Coder 和 Manager 继承 Employee 呢 ? 请同学们继续看继承的格式

    继承的格式 :

    在这里插入图片描述

    可以看到, 实现继承, 我们是通过 extends 关键字进行编写的 , 下面我们编写下代码

    • 示例代码 :
    class Employee {
        String name;
        int age;
        double salary;
    }
    
    class Coder extends Employee {
    
    }
    
    class Manager extends Employee {
    
    }
    
    public class Test {
        public static void main(String[] args) {
            Coder c = new Coder();
            c.name = "张三";
            c.age = 23;
            c.salary = 12000;
    
            System.out.println(c.name + "---" + c.age + "---" + c.salary);
    
            Manager m = new Manager();
            m.name = "李四";
            m.age = 24;
            m.salary = 18000;
    
            System.out.println(m.name + "---" + m.age + "---" + m.salary);
        }
    }
    
    • 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

    通过上面的代码, 同学们可以发现, Coder 和 Manager 中, 明明什么都没写, 但是却能够访问到父类 Employee 中的属性了

    所以, 重复的代码就不需要重复编写, 代码的复用性就提高了 ~

    但是, 我相信有些同学可能会想

    Q : 按照标准 JavaBean 来说, 成员变量不应该私有化吗 ? 那如果父类中的成员私有了, 子类岂不是用不到这些数据了.

    A : 能想到这个问题非常好, 说明之前的知识掌握的很扎实, 但是继续想, 我们私有成员变量之后, 会提供对应的 set 和 get 方法吧, 这些set \ get 可都是公共的, 子类是可以继承到直接用的

    • 示例代码 :
    package com.itheima.myextends;
    
    
    class Employee {
        private String name;
        private int age;
        private double salary;
    
    
        public Employee() {
        }
    
        public Employee(String name, int age, double salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
    }
    
    class Coder extends Employee {
    
    }
    
    class Manager extends Employee {
    
    }
    
    public class Test {
        public static void main(String[] args) {
            Coder c = new Coder();
            c.setName("张三");
            c.setAge(23);
            c.setSalary(12000);
            
            System.out.println(c.getName() + "---" + c.getAge() + "---" + c.getSalary());
    
            Manager m = new Manager();
            m.setName("李四");
            m.setAge(24);
            m.setSalary(18000);
    
            System.out.println(m.getName() + "---" + m.getAge() + "---" + m.getSalary());
        }
    }
    
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    2. 继承的好处和弊端

    好处 :

    通过上面的代码, 同学们感受到继承的什么好处了啊 ? 是的, 非常明显的发现, 代码的复用性提高了.

    除此之外呢, 继承还可以提高代码的维护性 , 这什么意思 ?

    假设, 我要在这款管理系统中, 加入一个 id 的属性, 那使用继承前, 我就需要在每一个类中, 挨个编写, 但是现在有了继承后, 我只需要在父类中编写一个 id, 所有的子类, 是不是就都具备了这个属性了 ? 是的 ! 这就提高了代码的维护性了 !
    在这里插入图片描述

    弊端 :

    继续刚刚的思路, 同学们可能会想, 增加一个, 所有子类都有了, 那删除一个, 岂不是所有子类都没有了啊…

    这不就牵一发而动全身了嘛… 是的, 这就是继承的弊端, 类的耦合性太强了.
    在这里插入图片描述

    何时使用继承 :

    聊到现在, 大家发现继承有好处, 也有弊端, 那该如何设计, 才能让利大于弊呢 ?
    在这里插入图片描述

    • 正确示例 :

    在这里插入图片描述

    • 错误示例 :

    在这里插入图片描述

    3. 继承中成员变量访问特点

    • 思考:子父类中,如果出现了重名的成员变量,使用的时候会优先使用??

    在这里插入图片描述

    • 运行效果 :
    20
    
    • 1
    • 原因 :

    在这里插入图片描述

    一定要使用父类的, 可以使用 super 关键字进行区分

    这里同学们可以先建立起一个使用思路

    • this. 调用本类成员
    • super.调用父类成员
    public class Zi extends Fu {
    	int num = 20;
        
        public void method(){
        	System.out.println(super.num);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    4. 继承中成员方法访问特点

    • 思考:子类继承了父类之后,是否可以自己继续定义方法?

    • 回答:当然可以, 子类继承父类, 是可以在继承到父类成员之后, 继续加东西的

    在这里插入图片描述

    • 问题 : 那子父类中, 要是出现了重名的成员, 逻辑却不一样呢 ?
    public class Fu {
    	public void method() {
           // 父类的方法
           System.out.println("父类method...");
        }
    }
    
    class Zi extends Fu {
        public void method() {
            System.out.println("子类method...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 运行结果 :
    子类method...
    
    • 1
    • 结论 :

      子父类中如果出现了重名的成员方法,优先使用子类的方法 , 但这其实是子类方法对父类方法进行了重写

    方法重写 Override :

    ​ 先跟大家聊聊什么是方法重写,在继承体系中,子类可以继承到父类的方法, 但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改, 这就需要采用方法的重写,方法重写又称方法覆盖

    在这里插入图片描述

    class Fu {
    	public void catch(){
    		System.out.println("使用弓箭捉羊...");
    	}
    }
    
    class Zi extends Fu {
    	@Override 
    	public void catch(){
    		System.out.println("使用98Kar狙击枪捉羊...");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 注意事项 :

    在这里插入图片描述

    解释 :

    父类中私有的方法, 子类访问不到, 就更不能重写了

    子类重写父类方法, 可以理解为是对功能进行增强, 那如果允许把访问权限降低, 那岂不是功能越做越差了嘛

    Java 中继承的特点 :

    ​ 了解了 Java 中方法重写后, 我们再来说下 Java 中继承的特点

    • 特点 : Java只支持单继承,不支持多继承,但支持多层继承

      • 其实就是说, 一个类, 最多只能有一个父类, 不能同时有多个父类
      class A {}
      
      class B {}
      
      class C extends A , B {}   // 编译出错
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 为什么 ? 因为担心逻辑冲突

    在这里插入图片描述

    • 问题 : 那多层继承呢 ?

    5. 继承中构造方法的访问特点

    • 思考问题 : 父类的构造方法, 子类能不能继承到呢 ?

    • 回答 : 不允许, 因为构造方法要求, 方法名和类名必须相同, 如果子类继承到父类的构造方法, 那方法名和类名就不一致了

    • 结论 : 子类不能继承父类的构造方法, 将来子类的构造方法, 需要自己编写

    public Fu {
    	public Fu(){}
    }
    
    class Zi extends Fu {
    	public Fu(){}   // 如果子类继承到父类的构造方法,  那方法名和类名就不一致了
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    继承中构造方法的访问流程
    • 阅读代码材料 :
    public class Test {
        public static void main(String[] args) {
            Zi z1 = new Zi();
            Zi z2 = new Zi(10);
        }
    }
    
    class Fu {
        public Fu() {
            System.out.println("Fu类空参构造方法");
        }
    
        public Fu(int num) {
            System.out.println("Fu类带参数构造方法");
        }
    }
    
    class Zi extends Fu {
    
        public Zi() {
            System.out.println("Zi类空参数构造方法");
        }
    
        public Zi(int num) {
            System.out.println("Zi类带参数构造方法");
        }
    
    }
    
    • 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
    • 运行效果 :
    Fu类空参构造方法
    Zi类空参数构造方法
    Fu类空参构造方法
    Zi类带参数构造方法
    
    • 1
    • 2
    • 3
    • 4

    通过打印效果同学们可以看出, 我们无论通过子类的哪一个构造方法创建对象, 都会执行到 Fu类的空参构造方法

    为什么 ? 因为在子类的构造方法, 第一行代码, 系统会默认帮我们加入 super ();

    通过super() 在访问父类的构造方法 , 现在我们手动把 super(); 加上, 同学们再阅读下试试吧~

    public class Test {
        public static void main(String[] args) {
            Zi z1 = new Zi();
            Zi z2 = new Zi(10);
        }
    }
    
    class Fu {
        public Fu() {
            System.out.println("Fu类空参构造方法");
        }
    
        public Fu(int num) {
            System.out.println("Fu类带参数构造方法");
        }
    }
    
    class Zi extends Fu {
    
        public Zi() {
        	super();
            System.out.println("Zi类空参数构造方法");
        }
    
        public Zi(int num) {
        	super();
            System.out.println("Zi类带参数构造方法");
        }
    
    }
    
    • 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

    okk, 看懂了执行流程之后, 新的问题来了, 我们知道学习这个细节, 对代码有什么帮助呢 ?

    答案是 : 子类将来可以把一部分数据, 交给父类初始化了

    我们来看一段代码

    public class Person {
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    • 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
    public class Student extends Person {
        private double score;
    
        public Student() {
        }
    
        public Student(String name, int age, double score) {
            super(name, age);
            this.score = score;
        }
    
        public double getScore() {
            return score;
        }
    
        public void setScore(double score) {
            this.score = score;
        }
    
        public void study() {
            System.out.println(
                    "姓名为" + super.getName()
                    + ", 年龄为" + super.getAge()
                    + ", 成绩为" + score + "分的学生, 正在学习Java");
        }
    }
    
    
    • 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
    public class ExtendsTest2 {
        public static void main(String[] args) {
            Student stu = new Student("李四", 24, 100);
            stu.study();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在上述代码中, 我们可以发现, main方法中 , 创建学生对象, 我们给了 3个参数, 先执行子类的带参数构造方法

    其中前两个数据, 我们通过super, 交给了父类初始化, 最后一个成绩数据, 父类没有, 子类自己完成了初始化

    public Student(String name, int age, double score) {	// "李四", 24, 100
            super(name, age);	// "李四", 24 交给父类
            this.score = score; // 100 子类自己初始化
    }
    
    • 1
    • 2
    • 3
    • 4

    配合一张内存图 , 大家再看一下

    在这里插入图片描述

    这里我们可以发现, 堆内存的对象中, 会存在一个 super 区域, 专门存放父类的成员

    所以, 前两个数据, 父类中有, 就交给父类初始化, 最后一个数据, 父类没有, 子类就自己完成初始化.

    6. this 和 super

    上述文章中, 我们其实关于 this 和 super 做了很多使用了, 接下来我们来梳理下

    • this:代表本类对象的引用

    • super:代表父类存储空间的标识(可以理解为父类对象引用)

    在这里插入图片描述

    好啦, 本次关于继承的技术, 就跟大家聊到这里了

    我们下次再见 ~

    掰掰~ ()

  • 相关阅读:
    基于51单片机超市称重电子秤proteus仿真
    RefConv: 重参数化的重新聚焦卷积(论文翻译)
    关于node安装和nvm安装的问题
    基于双级阈值及过零率的语音激活检测(VAD)
    Linux常用指令总结
    万字长文,带你彻底搞懂 HTTPS(文末附实战)
    Stable Diffusion AI绘图使用记录
    呆头鹅-全自动视频混剪,批量剪辑批量剪视频,探店带货系统,精细化顺序混剪,故事影视解说,视频处理大全,精细化顺序混剪,多场景裂变,多视频混剪
    Vue2 +Element-ui实现前端页面
    如何规划好自己的工作与学习时间?助你提高办事效率的待办提醒软件
  • 原文地址:https://blog.csdn.net/cz_00001/article/details/126707440