2022(终)最后一篇博客—继承和多态

news2024/9/24 17:09:38

目录

文章目录

一、继承

1.1为什么要继承

1.2继承概念

1.3继承的语法

1.4成员访问

1.5方法访问

1.6初始化代码块

1.7继承方式

二、多态

1.1多态的概念

1.2多态实现条件

1.3动态绑定与静态绑定

1.4向上转型与向下转型

1.5多态的优缺点

1.6需要注意的地方:避免在构造方法中调用重写的方法


一、继承

1.1为什么要继承

一句话总结来说:就是对共性进行抽取,进行代码的复用

1.2继承概念

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

1.3继承的语法

在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下:

修饰符 class 子类 extends 父类 {
// ...
}

举例:

public class Animal{
String name;
int age;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
} 

public class Dog extends Animal{
void bark(){
System.out.println(name + "汪汪汪~~~");
}
}

public class Cat extends Animal{
void mew(){
System.out.println(name + "喵喵喵~~~");
}
} 

public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
// dog类中并没有定义任何成员变量,name和age属性肯定是从父类Animal中继承下来的
System.out.println(dog.name);
System.out.println(dog.age);
// dog访问的eat()和sleep()方法也是从Animal中继承下来的
dog.eat();
dog.sleep();
dog.bark();
}
}

注意:
1. 子类会将父类中的成员变量或者成员方法继承到子类中了
2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

1.4成员访问

public class Base {
int a;
int b;
int c;
} 

public class Derived extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; 
b = 101; 
c = 102; 
}
}

在子类方法中 或者 通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。

成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找
 

1.5方法访问

public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}

public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
}
}
  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。
  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错。

1.6初始化代码块

在没有继承关系下的代码块的执行顺序是:

  • 静态代码块执行
  • 实例代码块执行
  • 构造方法执行
  1.  静态代码块先执行,并且只执行一次,在类加载阶段执行
  2.  当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行

那么在继承关系下的代码块执行顺序是什么样子呢?下面我来举个例子:

class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
} {
System.out.println("Person:实例代码块执行");
} 
static {
System.out.println("Person:静态代码块执行");
}
}

class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
} {
System.out.println("Student:实例代码块执行");
} 
static {
System.out.println("Student:静态代码块执行");
}
}

public class TestDemo4 {
public static void main(String[] args) {
Student student1 = new Student("张三",19);
System.out.println("===========================");
Student student2 = new Student("xyk",20);
}

执行结果:

Person:静态代码块执行
Student:静态代码块执行
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
===========================
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行

通过分析执行结果,得出以下结论:
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行

1.7继承方式

在java中只支持以下几种继承方式:

注意:Java中不支持多继承。
 

二、多态

1.1多态的概念

多态的概念:

  • 通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
  • 总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。

1.2多态实现条件

在java中要实现多态,必须要满足如下几个条件,缺一不可:
1. 必须在继承体系下
2. 子类必须要对父类中方法进行重写
3. 通过父类的引用调用重写的方法

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

下面来举个例子:

public class Animal {
String name;
int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name + "吃饭");
}
}

public class Cat extends Animal{
public Cat(String name, int age){
super(name, age);
} 
@Override
public void eat(){
System.out.println(name+"吃鱼~~~");
}
}

public class Dog extends Animal {
public Dog(String name, int age){
super(name, age);
} 
@Override
public void eat(){
System.out.println(name+"吃骨头~~~");
}
}

public class TestAnimal {
public static void eat(Animal a){
a.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("元宝",2);
Dog dog = new Dog("小七", 1);
eat(cat);
eat(dog);
}
} 

运行结果:
元宝吃鱼~~~
元宝正在睡觉
小七吃骨头~~~
小七正在睡觉

1.3动态绑定与静态绑定

  • 静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
  • 动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

1.4向上转型与向下转型

向上转型:

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()

Animal animal = new Cat("元宝",2);

向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法。

向下转型:

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

1.5多态的优缺点

【使用多态的好处】
1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else
什么叫 "圈复杂度" ?
圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂.
因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 "圈复杂度".如果一个方法的圈复杂度太高, 就需要考虑重构.
不同公司对于代码的圈复杂度的规范不一样. 一般不会超过10

2. 可扩展能力更强
如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低

下面举个运用多态的例子:

class Shape {
//属性....
public void draw() {
System.out.println("画图形!");
}
}

class Rect extends Shape{
@Override
public void draw() {
System.out.println("♦");
}
}

class Cycle extends Shape{
@Override
public void draw() {
System.out.println("●");
}
}

class Flower extends Shape{
@Override
public void draw() {
System.out.println("❀");
}
}

public static void drawShapes() {
// 我们创建了一个 Shape 对象的数组.
Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),
new Rect(), new Flower()};
for (Shape shape : shapes) {
shape.draw();
}
}

多态缺陷:代码的运行效率降低。
1. 属性没有多态性
当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性
2. 构造方法没有多态性

1.6需要注意的地方:避免在构造方法中调用重写的方法

一段有坑的代码. 我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func

class B {
public B() {
// do nothing
func();
}
public void func() {
System.out.println("B.func()");
}
}

class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}

public class Test {
public static void main(String[] args) {
D d = new D();
}
}

// 执行结果
D.func() 0
  • 构造 D 对象的同时, 会调用 B 的构造方法.
  • B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
  • 此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0. 如果具备多态性,num的值应该是1.
  • 所以在构造函数内,尽量避免使用实例方法,除了final和private方法。

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

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

相关文章

【王道操作系统】1.1.2 操作系统的特征(并发、共享、虚拟、异步)

操作系统的特征(并发、共享、虚拟、异步) 文章目录操作系统的特征(并发、共享、虚拟、异步)1.操作系统特征:并发2.操作系统特征:共享3.操作系统特征:虚拟4.操作系统特征:异步操作系统是一种系统软件,但与其它系统软件和…

NXP的mfgtool镜像烧写工具是如何对EMMC进行分区的

本来是想在IMX6ULL板卡上实现u-boot中显示开机logo的功能的,过程中就牵扯出了这几个问题。大概的缘由是修改了u-boot后,想在系统中直接对EMMC中u-boot进行更新,就不用通过SD卡或USB重新烧写了;在更新的时候,又需要知道…

猿如意程序代码生成实践与测试

ChatGPT中国区申请无法直接注册与使用; 使用csdn提供的猿如意效率工具箱提供的chatGPU功能实现智能程序编写实验: 先安装: csdn猿如意下载地址 选择其中的ChatGPT菜单 在右侧窗口中的输入框,可输入问题内容。 (1&a…

〖产品思维训练白宝书 - 产品思维认知篇⑥〗- 职场人面临困惑与迷茫应该如何破局?

大家好,我是 哈士奇 ,一位工作了十年的"技术混子", 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬 &#x1f4e…

Leetcode:459. 重复的子字符串(C++)

目录 问题描述: 实现代码与解析: 移动匹配法: 原理思路: 利用kmp法: 原理思路: 暴力法: 原理思路: 问题描述: 给定一个非空的字符串 s ,检查是否可以…

55 处理错误的树形数据结构导致不断地添加元素到集合中 OOM

前言 呵呵 这是最近一个 前同事/朋友 碰到的一个问题 主要的问题是 在 dump 文件中发现了很多 LinkedList$Node 的节点 然后 整个问题 抛出来的错误是 OOM 呵呵 这种问题 还是相当好处理的 这里 仅仅是 简单记录一下 前因 后果 测试用例 /*** Test11OomByTree** aut…

关于2022年

也算是传统了,每年到年底的时候,总喜欢做点总结,或许类似于企业里面的年底复盘,但更多的还是碎碎念。往年一般会放在农历新年那一天,今年做点小改变,影响不大。 回顾过去的一年,发现自己基本上…

【HR-VITON】虚拟换衣算法pre-processing复现全过程记录

Link of original Github repo Link of personal made study case of HR-VITON ContentPre1、OpenPose(On colab, need GPU)2、Human ParseMethod 1: ColabMethod 2: Local or Server3、DensePose (On colab, GPU or CPU)4、Cloth Mask (On colab, GPU o…

【MySQL】InnoDB数据页结构

文章目录1. 前言2. 数据页结构3. 记录在页中的存储4. 记录头信息5. 页目录(Page Directory)6. 页面头部(Page Header)7.文件头部(Fiile Header)8. 文件尾部(File Trailer)不知不觉20…

JVM调优相关说明

前言 其实听着JVM调优这个词有些高大上,但是等你真正了解了他的内在原理后,还是很容易的。再简单 JVM调优大致可分为如下: 解决JVM运行过程中的问题(主要就是内存溢出的问题)优化JVM运行时的环境,提高运…

多线程问题(四)

目录 一、常见的锁策略 1、乐观锁 VS 悲观锁 2、读写锁 VS 普通的互斥锁 3、重量级锁 VS 轻量级锁 4、挂起等待锁 VS 自旋锁 6、公平锁 VS 非公平锁 7、可重入锁 VS 不可重入锁 8、synchronized锁的性质 二、CAS 1、CAS的伪代码 2、CAS的应用 a、实现原子类…

【Spring系列】一篇文章开启你的 SpringBoot 之旅

SpringBoot 快速入门一. 环境搭建1.1 环境准备Java环境准备(本人是 JDK 1.8)开发工具 IntelliJ IDEAMaven (可使用 IntelliJ IDEA 自带)二. 快速开始2.1 新建项目打开IDEA 新建 SpringBoot 项目2.2 运行项目Spring Boot 项目运行分析尝试在浏览器中访问2.3 完成第一个接口新建c…

ArcGIS基础实验操作100例--实验30清除坐标系信息

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 高级编辑篇--实验30 清除坐标系信息 目录 一、实验背景 二、实验数据 三、实验步骤 方法一&#xff…

运维管理平台OEM定制集成开发,激发IT价值

对硬件设备商而言,借助优秀的网管、运维管理平台,可以形成完整的产品解决方案,直接提升产品的形象和适用范围。同时还可以通过网管、运维管理平台,切入到外围的产品及集成领域,并在用户后续的升级改造活动中占据有利位…

12.31日报

纠正前天的错误: 前天我写: 不知道在mapper中的增删改方法返回值int的值,和含义,在调用方法时也没有定义int来接参,都是直接调用。于是我定义int i,并打印输出,使用postman调用接口方法&#xf…

R语言hdnom包进行高维惩罚 Cox 回归模型绘制列线图-校准曲线-时间依赖ROC-外部验证

Hdnom包可以用于用于给高维数据构建Cox 模型、绘制列线图-校准曲线-时间依赖ROC-外部验证,而且Hdnom包简化了建模过程,带有自动选择变量功能,将用户从繁琐且容易出错的调参过程中解放出来. hdnom提供了多项自动调参和模型选择功能&#xff…

【OpenAI】基于 Gym-CarRacing 的自动驾驶项目 | 前置知识介绍 | 项目环境准备

猛戳!跟哥们一起玩蛇啊 👉 《一起玩蛇》🐍 💭 写在前面: 本篇是关于多伦多大学自动驾驶专业项目 Gym-CarRacing 的博客。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行…

jscharting.js v3.3.1.20220428 Crack

jscharting.js 3.3 版带来了主要的新组织结构图和甘特图扩展,包括甘特关键路径图、组织连接线样式和选择、仪表板小部件、象形图等等。图表渐变支持扩展到包括图标和动态点和系列渐变填充。 JSCharting 团队使用新功能、图表类型和图表小部件制作了超过 55 个高级示…

从发展的趋势来看,数字技术理应是产业互联网时代的驱动力

事实上,以往,我们所经历的那个互联网玩家频出的年代,其实就是一个以互联网技术为主导的年代。在那样一个年代里,互联网技术几乎是解决一切痛点和难题的万能解药,几乎是破解一切行业痛点和难题的杀手锏。任何一个行业&a…

【Java语言】—顺序结构、分支结构

流程控制语句 Java提供了一些流程控制语句,来控制程序的执行流程。 1.顺序结构 按照代码的先后顺序,以此执行程序。 2.分支结构 (1)if分支 根据判断的结果(真或假)决定执行某个分支的代码。 if分支有三…