面向对象 - 继承

news2025/1/23 3:54:44

Hello , 各位同学朋友大家好啊, 今天给大家分享的技术呢, 是面向对象三大特征之一的继承,我们今天主要按照以下几个点, 展开继承的讲解。

  目录 :

  * 继承的介绍

  * 继承的好处和弊端

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

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

  * 方法重写

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

  * this 和 super 关键字

继承的介绍

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

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

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

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

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

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

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

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

  继承的格式 :

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

  示例代码 :

classEmployee{String name;int age;double salary;}classCoderextendsEmployee{}classManagerextendsEmployee{}publicclassTest{publicstaticvoidmain(String[] args){Coder c =newCoder();
        c.name ="张三";
        c.age =23;
        c.salary =12000;System.out.println(c.name +"---"+ c.age +"---"+ c.salary);Manager m =newManager();
        m.name ="李四";
        m.age =24;
        m.salary =18000;System.out.println(m.name +"---"+ m.age +"---"+ m.salary);}}
```

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

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

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

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

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

  示例代码 :

packagecom.itheima.myextends;classEmployee{privateString name;privateint age;privatedouble salary;publicEmployee(){}publicEmployee(String name,int age,double salary){this.name = name;this.age = age;this.salary = salary;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicdoublegetSalary(){return salary;}publicvoidsetSalary(double salary){this.salary = salary;}}classCoderextendsEmployee{}classManagerextendsEmployee{}publicclassTest{publicstaticvoidmain(String[] args){Coder c =newCoder();
        c.setName("张三");
        c.setAge(23);
        c.setSalary(12000);System.out.println(c.getName()+"---"+ c.getAge()+"---"+ c.getSalary());Manager m =newManager();
        m.setName("李四");
        m.setAge(24);
        m.setSalary(18000);System.out.println(m.getName()+"---"+ m.getAge()+"---"+ m.getSalary());}}

```

  2. 继承的好处和弊端

  好处 :

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

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

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

  弊端 :

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

   这不就牵一发而动全身了嘛... 是的, 这就是继承的弊端, 类的耦合性太强了。

  何时使用继承 :

  聊到现在, 大家发现继承有好处, 也有弊端, 那该如何设计, 才能让利大于弊呢 ?

  正确示例 :

  错误示例 :

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

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

  运行效果 :

  原因 :

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

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

  this. 调用本类成员

  super.调用父类成员

publicclassZiextendsFu{int num =20;publicvoidmethod(){System.out.println(super.num);}}
```

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

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

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

  * 问题 : 那子父类中, 要是出现了重名的成员, 逻辑却不一样呢 ?

publicclassFu{publicvoidmethod(){// 父类的方法System.out.println("父类method...");}}classZiextendsFu{publicvoidmethod(){System.out.println("子类method...");}}
```

  * 运行结果 :

子类method...
```

  结论 :

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

  方法重写 Override :

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

  

classFu{publicvoidcatch(){System.out.println("使用弓箭捉羊...");}}classZiextendsFu{@Overridepublicvoidcatch(){System.out.println("使用98Kar狙击枪捉羊...");}}
```

  注意事项 :

  > 解释 :

  >

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

  >

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

  Java 中继承的特点 :

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

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

  * 其实就是说, 一个类, 最多只能有一个父类, 不能同时有多个父类

classA{}classB{}classCextendsA,B{}// 编译出错
  ```

  * 为什么 ? 因为**担心逻辑冲突**

  

* 问题 : 那多层继承呢 ?

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

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

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

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

publicFu{publicFu(){}}classZiextendsFu{publicFu(){}// 如果子类继承到父类的构造方法,  那方法名和类名就不一致了}
```

  继承中构造方法的访问流程

  * 阅读代码材料 :

publicclassTest{publicstaticvoidmain(String[] args){Zi z1 =newZi();Zi z2 =newZi(10);}}classFu{publicFu(){System.out.println("Fu类空参构造方法");}publicFu(int num){System.out.println("Fu类带参数构造方法");}}classZiextendsFu{publicZi(){System.out.println("Zi类空参数构造方法");}publicZi(int num){System.out.println("Zi类带参数构造方法");}}
```

  * 运行效果 :

Fu类空参构造方法
Zi类空参数构造方法
Fu类空参构造方法
Zi类带参数构造方法
```

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

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

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

publicclassTest{publicstaticvoidmain(String[] args){Zi z1 =newZi();Zi z2 =newZi(10);}}classFu{publicFu(){System.out.println("Fu类空参构造方法");}publicFu(int num){System.out.println("Fu类带参数构造方法");}}classZiextendsFu{publicZi(){super();System.out.println("Zi类空参数构造方法");}publicZi(int num){super();System.out.println("Zi类带参数构造方法");}}
```

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

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

  我们来看一段代码

publicclassPerson{privateString name;privateint age;publicPerson(){}publicPerson(String name,int age){this.name = name;this.age = age;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}}
```

```java
publicclassStudentextendsPerson{privatedouble score;publicStudent(){}publicStudent(String name,int age,double score){super(name, age);this.score = score;}publicdoublegetScore(){return score;}publicvoidsetScore(double score){this.score = score;}publicvoidstudy(){System.out.println("姓名为"+super.getName()+", 年龄为"+super.getAge()+", 成绩为"+ score +"分的学生, 正在学习Java");}}

```

```java
publicclassExtendsTest2{publicstaticvoidmain(String[] args){Student stu =newStudent("李四",24,100);
        stu.study();}}
```

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

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

publicStudent(String name,int age,double score){// "李四", 24, 100super(name, age);// "李四", 24 交给父类this.score = score;// 100 子类自己初始化}
```

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

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

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

  6. this 和 super

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

  this:代表本类对象的引用

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文认知并发安全的几种解决方案与性能对比

Kotlin协程基本套餐:协程的基本使用协程的上下文理解协程的作用域管理协程的常见进阶使用之前的系列文章我们讲的是一些 Kotlin 协程的基本概念和一些实用与常用的技巧与方法。其实明白之后,基本的使用是没有问题了。那么今天我想探讨一下,没…

用gin写简单的crud后端API接口

提要使用gin框架(go的web框架)来创建简单的几个crud接口)使用技术: gin sqlite3 sqlx创建初始工程新建文件夹,创建三个子文件夹分别初始化工程 go mod如果没有.go文件,执行go mod tidy可能报错(warning: "all" matched no packages), 可以先不弄,只初始化模块就行(…

GreenPlum小结

什么是GreenPlum?GreenPlum是业界最快最高性价比的关系型分布式数据库,它在开源的PostgreSQL的基础上采用MPP架构(Massive Parallel Processing,海量并行处理),具有强大的大规模数据分析任务处理能力。GreenPlum作为大数据融合存储…

【UE4 RTS游戏】03-摄像机运动_旋转视角

效果可以通过WASD控制“CameraPawn”的移动;通过鼠标中键旋转视角;通过alt鼠标中键将视角回归默认值;通过shift加速移动。步骤打开“CameraPawnController”,给如下节点添加注释,命名为“MovementX”接下来开始开始编辑…

JDK解压安装及idea开发工具配置

1. 安装JDK 1.1 下载安装包 下载安装包,直接解压,注意,解压的路径不要有中文 1.2 配置环境变量 右键点击我的电脑,选择属性 选择高级系统设置 选择环境变量 选择新建 在变量名中输入JAVA_HOME,变量值就是1.1中压缩包…

Windows环境下实现设计模式——访问者模式(JAVA版)

我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下如何编程实现访问者模式(设计模式)。不知道大家有没有这样的感觉,看了一大堆编程和设计模式的书,却还是很难理解设计模式&#xff0c…

【C++】类和对象(收尾)

文章目录成员变量初始化问题初始化列表explicit关键字static成员特性:友元友元函数友元类内部类特性匿名对象成员变量初始化问题 在创建对象时,编译器通过调用构造函数,给了对象中各个成员变量一个合适的初始值。但是这并不能够称为对对象中成…

简单了解蓄电池在直流系统中的使用现状!

一般情况下,由市电通过直流配电屏为变电站的直流系统提供工作电源,包括对蓄电池组进行饱和和充电使蓄电池处于备用状态,当交流失电或系统需要进行大电流供电时,蓄电池需要迅速切入,向事故负荷、自动装置、保护装置以及…

本地套接字

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 本地套接字专栏:《Linux从小白到大神》《网络编程》 本地套接字通信需要一个文件&#xff…

tensorflow【import transformers 报错】

目录 一、安装 安装好了tensorflow,但是import时候报错: import transformers 报错 一、安装 (1)创建环境: conda create -n [name] python3.3-3.7 (2)激活环境: conda activate [name] …

Python中赋值、引用、深浅拷贝的区别和联系

文章目录一、对象的唯一id二、赋值三、可变对象和不可变对象四、函数的参数传递五、深拷贝和浅拷贝六、举个栗子6.1 不可变对象的拷贝6.2 可变对象的拷贝6.3 可变对象改变外层元素6.4 可变对象改变内层元素七、总结一、对象的唯一id python中的所有对象都有自己的唯一id&#…

典型回溯题目 - 全排列(一、二)

典型回溯题目 - 全排列(一、二) 46. 全排列 题目链接:46. 全排列状 题目大意: 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 注意:(1&#xf…

Linux命令·which·whereis·locate·find

我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which 查看可执行文件的位置。whereis 查看文件的位置。 locate 配合数据库查看文件位置。find 实际搜寻硬盘查询文件名称。whichwhich命令的作用是&#x…

DJ1-1 操作系统引论

目录 一、操作系统的概念 二、操作系统的目标 三、操作系统的作用 一、操作系统的概念 定义一 操作系统是一组控制和管理计算机软硬件资源、合理地对各类作业进行调度以及方便用户使用的程序集合。 定义二 操作系统是位于硬件层(HAL)之上&#xff…

SQL 基础函数,通配符,BETWEEN ,用法复习

使用 SQL _ 通配符 下面的 SQL 语句选取 name 以一个任意字符开始,然后是 “oogle” 的所有客户: SELECT * FROM Websites WHERE name LIKE _oogle;下面的 SQL 语句选取 name 以 “G” 开始,然后是一个任意字符,然后是 “o”&am…

看完这篇我不信你不会二叉树的层序遍历【C语言】

目录 实现思路 代码实现 之前介绍了二叉树的前、中、后序三种遍历,采用的是递归的方式。今天我们来学习另外一种遍历方式——层序遍历。层序遍历不容小觑,虽然实现方法并不难,但是它所采取的思路是很值得学习的,与前三者不同&am…

学习笔记-架构的演进之容器的封装-3月day06

文章目录前言封装应用的Dockerwhy Docker not LXC?附前言 当文件系统、访问、资源都可以被隔离后,容器就已经具备它降生所需要的全部前置支撑条件了。为了降低普通用户综合使用 namespaces、cgroups 这些低级特性的门槛,2008 年 Linux Kernel 2.6.24 内…

Java中的final和权限修饰符

目录 final 常量 细节: 权限修饰符 Java权限修饰符用于控制类、方法、变量的访问范围。Java中有四种权限修饰符: 权限修饰符的使用场景: final 方法 表明该方法是最终方法,不能被重写。类 表明该类是最终类,不能被继…

Jetpack太香了,让开发效率提升了不少

作者:Jingle_zhang 第三方App使用Jetpack等开源框架非常流行,在Gradle文件简单指定即可。然而ROM内置的系统App在源码环境下进行开发,与第三方App脱节严重,采用开源框架的情况并不常见。但如果系统App也集成了Jetpack或第三方框架…

【UE4 RTS游戏】04-摄像机运动_鼠标移动到视口边缘时移动Pawn

效果可以看到当鼠标移动到视口边缘时,Pawn就会向这个方向移动。步骤打开项目设置,添加两个操作映射打开“CameraPawnController”,在事件图表中添加两个浮点型变量,一个为公有一个为私有。分别命名为“ZoomSensitivity”、“MaxAr…