【Java0基础学Java第八颗】 -- 继承与多态 -- 多态
8.继承与多态
- 8.2 多态
- 8.2.1 多态的概念
- 8.2.2 多态实现条件
- 8.2.3 重写
- 8.2.4 向上转型和向下转型
- 8.2.5 向下转型
- 8.2.6 多态的优缺点
- 8.2.7 避免在构造方法中调用重写的方法
8.2 多态
8.2.1 多态的概念
通俗来说就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
就比如打印机,彩色打印机和黑白打印机,打印出的效果一个是彩色,一个是黑白。
即:同一件事情,发生在不同对象身上,就会产生不同的结果。
8.2.2 多态实现条件
在Java中要实现多态,必须要满足以下条件:
- 必须在继承体系下
- 子类必须要对父类方法进行重写
- 通过父类的引用调用重写的方法
多态的体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。
8.2.3 重写
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, **返回值和形参都不能改变。即外壳不变,核心重写!**重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写的规则:
- 方法名一样
- 参数列表相同(个数、数据类型、顺序)
- 返回值一样
注意: 不能被重写的4种情况
- 被final修饰的方法 不可以被重写。这个方法叫做密封方法。
public final void eat() {System.out.println(this.name+" 正在吃。。。");}
- 被static修饰的方法 不能被重写
public static void eat() {System.out.println(this.name+" 正在吃。。。");}
- 子类重写父类方法的时候,子类的方法访问修饰限定符要>=父类
// 父类的方法
//当父类的方法修饰限定符是 默认defau时,子类的方法访问修饰限定符可以是protected、public
public void eat() {System.out.println(this.name+" 正在吃。。。");}//子类的方法
public void eat() {System.out.println(this.name+" 正在吃狗粮...");}
-
- 被private修饰的方法 是不被重写的
重写和重载的区别:
重写的方法名和参数都一样,而重载的方法名相同,参数不同。
即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
通过反汇编代码:
动态绑定:子类和父类都有 编译得时候认为 还是确认调用了父类得eat方法
运行得时候 绑定到子类当中
- 父类引用 引用 子类对象;
- 通过父类引用 去调用 父类 和子类 同名的方法。
静态绑定:编译的时候就已经确定调用哪个方法了,如下dog.barks(10);
8.2.4 向上转型和向下转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
- 直接赋值
Animal animal = new Dog("旺财",10,"红色"); //直接赋值
- 方法传参
// 方法传参 :形参作为父类引用,可以接受任意子类的对象public static void fun(Animal animal) {animal.eat();// 发生了多态}public static void main(String[] args) {Dog dog = new Dog("旺财",3,"红色");fun(dog);Bird bird = new Bird("布谷",1);fun(bird);}
同一个引用 调用了 同一个方法,当是因为引用的对象不一样,所表现的行为不一样,称为多态。
- 方法返回
// 通过返回值,进行向上转型public static Animal fun2() {return new Dog("旺财",3,"红色");}
向下转型能让代码变得更加简单灵活,缺点就是不能调用到子类特有的方法。
8.2.5 向下转型
Java中为了提高向下转型的安全性,引入了instanceof ,如果该表达式为true,则可以安全转换。
public static void main(String[] args) {Animal animal2 = new Bird("布谷",1);//animal2.eat();//animal2.fly();Bird bird = (Bird) animal2;bird.fly();Animal animal1 = new Dog("旺财",3,"红色");if (animal1 instanceof Bird) {Bird bird2 = (Bird) animal1;bird2.fly();}else {System.out.println("不一定所以的动物都是鸟");}}
8.2.6 多态的优缺点
使用多态的好处:
- 能够降低代码的圈复杂度,避免使用大量的if-else
用if-else:
class Shape {public void draw() {System.out.println("画图形");}
}
class Cycle extends Shape {@Overridepublic void draw() {System.out.println("⚪");}
}
class Rect extends Shape {@Overridepublic void draw() {System.out.println("矩形");}
}class Triangle extends Shape {@Overridepublic void draw() {System.out.println("三角形");}
}
public class Test {public static void main(String[] args) {Rect rect = new Rect();Cycle cycle = new Cycle();Triangle triangle = new Triangle();String[] shapes = {"cycle", "rect", "cycle", "rect", "triangle"};for (String shape : shapes) {if (shape.equals("cycle")) {cycle.draw();} else if (shape.equals("rect")) {rect.draw();} else if (shape.equals("triangle")) {triangle.draw();}}}}
用多态:
class Shape {public void draw() {System.out.println("画图形");}
}
class Cycle extends Shape {@Overridepublic void draw() {System.out.println("⚪");}
}
class Rect extends Shape {@Overridepublic void draw() {System.out.println("矩形");}
}class Triangle extends Shape {@Overridepublic void draw() {System.out.println("三角形");}
}
public class Test {// 使用多态public static void main(String[] args) {Rect rect = new Rect();Cycle cycle = new Cycle();Triangle triangle = new Triangle();// 向上转型Shape[] shapes = {cycle,rect,cycle,rect,triangle};for (Shape shape : shapes) {shape.draw();}}
}
- 可扩展能力更强
如果需要新加一种形状,使用多态的方式代码改动成本也比较低
比如新加一个画❀
class Flower extends Shape {@Overridepublic void draw() {System.out.println("❀");}
}
public class Test {public static void main(String[] args) {Rect rect = new Rect(); // 相当于Shape rect = new Rect();Cycle cycle = new Cycle();Triangle triangle = new Triangle();Flower flower = new Flower();// 向上转型Shape[] shapes = {cycle,rect,cycle,rect,triangle,flower};for (Shape shape : shapes) {shape.draw();}}
}
缺点: 代码的运行效率降低
- 属性没有多态性
当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性 - 构造方法没有多态性
8.2.7 避免在构造方法中调用重写的方法
当在父类的构造方法当中,调用父类和子类同名的方法时候,此时也会发生动态绑定。也意味着 构造方法内 也会发生动态绑定。
注意: 在构造方法当中 不要调用重写的方法。
class B {public B() {// 父类的实例 --> 父类的构造 --> 子类的实例 --> 子类的构造func(); // 调用子类的func方法 没有给num赋值 所以num的值为0}public void func() {System.out.println("B.func()");}
}
class D extends B {private int num = 1;public D() {super();}@Overridepublic void func() {System.out.println("D.func() " + num);}
}
public class Test2 {public static void main(String[] args) {//1. 分配内存空间 2. 调用合适的构造方法D d = new D();}
}
- 构造 D 对象的同时, 会调用 B 的构造方法.
- B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
- 此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0.。
- 所以在构造函数内,尽量避免使用实例方法,除了final和private方法。
结论:用尽量简单的方式使对象进入可工作状态,尽量不要在构造器中调用方法(如果这个方法被子类重写,就会触发动态绑定,但是此时子类对象还没构造完成),可能会出现一些隐藏的但是又极难发现的问题。
相关文章:

【Java0基础学Java第八颗】 -- 继承与多态 -- 多态
8.继承与多态 8.2 多态8.2.1 多态的概念8.2.2 多态实现条件8.2.3 重写8.2.4 向上转型和向下转型8.2.5 向下转型8.2.6 多态的优缺点8.2.7 避免在构造方法中调用重写的方法 8.2 多态 8.2.1 多态的概念 通俗来说就是多种形态,具体点就是去完成某个行为,当…...

玩转ansible之参数调试和文件操作篇
更多IT技术文章,欢迎关注微信公众号“运维之美” 玩转ansible之参数调试和文件操作篇 01 剧本调试和帮助02 使用场景举例 上节我们学习了使用ansible进行软件安装,那么安装完软件后,就需要linux系统和软件配置修改了,对于linux主机…...

JVM虚拟机:垃圾回收器之Parallel Old(老年代)
本文重点 本文将学习老年代的另外一种垃圾回收器Parallel Old(PO),这是一种用于老年代的并行化垃圾回收器,它使用标记整理算法进行垃圾回收。 历史 在1.6之前,新生代使用Parallel Scavenge只能搭配老年代的Serial Old收集器,而…...
Stream流的groupingBy
Stream流的groupingBy 简单使用 业务场景:现在有100个人,这些人都年龄分部在18-30岁之间。现要求把他们按照年龄进行分组 key:年龄 value:数据列表 public void listToMapGroup() {//这里假设通过listStreamService.list();方法…...
如何在不结束tcpdump的情况下复制完整的pcap
tcpdump正在运行的时候,他写入的pcap可能是不完整的,通常我们要结束掉tcpdump才能拿到完整的pcap,否则wireshark打开的时候会提示:The capture file appears to have been cut short in the middle of a packet。这可能是因为tcpd…...
maven POM文件总体配置说明
<project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd "> <!-- 父项目的坐…...
49.批处理命令(1/2)
目录 一批处理。 (1)批处理定义。 (2)常见命令。 (2.1)rem和:: (2.2)echo和。 (2.3)pause。 (2.4)errorlevel。 (…...

react类式组件的生命周期和useEffect实现函数组件生命周期
概念 生命周期是一个组件丛创建,渲染,更新,卸载的过程,无论是vue还是react都具有这个设计概念,也是开发者必须熟练运用的,特别是业务开发,不同的生命周期做不同的事是很重要的. ....多说两句心得,本人是先接触vue的,无论是vue2还是vue3的生命周期,在理解和学习上都会比react更…...

ARM 基础学习记录 / 异常与GIC介绍
GIC概念 念课本(以下内容都是针对"通用中断控制器(GIC)"而言,直接摘录的,有的地方可能不符人类的理解方式): 通用中断控制器(GIC)架构提供了严格的规范&…...
java压缩pdf体积,图片体积
pdf整体进行压缩,图片进行压缩 // 生成主证书的PDF路径 创建一个文件String pdfPath UploadDown.createFile(".pdf");outputStream new FileOutputStream(pdfPath);bufferedOutputStream new BufferedOutputStream(outputStream);writer PdfWriter.getInstance(…...
Ubuntu(WSL2) 安装最新版本的 GCC
要在 Ubuntu 上安装最新版本的 GCC,可以通过以下步骤进行操作: 1. 打开终端(Terminal) 2. 更新软件包列表,确保系统使用最新的软件包信息,运行以下命令: sudo apt update 3. 安装 GCC 软件包…...

lua 时间差功能概略
简介 在进行程序设计过程中,经常需要对某些函数、某些程序片断从开始运行到运行结束所耗费的时间进行一些量化。这种量化实际上就是计算时间差。 获取函数耗时情景如下: function time_used() --开始计时-- do something at here. --结束计时--时间差&…...
【C++11】左值引用,右值引用,移动/复制构造,完美转发
左值与右值 字面意思是可以放在等号左边的就是左值,只能放在等号右边的就是右值(为何是“可以”“只能”?例如i是左值,但他依然可以放在等号右边)。 严格上的定义:可以取地址的就是左值,反之为…...

解决找不到x3daudio1_7.dll的方法,快速解决x3daudio1_7.dll丢失问题
在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是“找不到x3daudio1_7.dll”。这个问题可能是由于多种原因引起的,例如文件丢失、损坏或被病毒感染等。下面将详细介绍如何解决这个问题。 首先,我们需要了解x3daudio1_…...
LeetCode:2300. 咒语和药水的成功对数(C++)
目录 2300. 咒语和药水的成功对数 题目描述: 实现代码与解析: 二分 原理思路: 2300. 咒语和药水的成功对数 题目描述: 给你两个正整数数组 spells 和 potions ,长度分别为 n 和 m ,其中 spells[i] 表…...
【Spring生命周期核心底层源码之剖析】
文章目录 一、Spring生命周期核心底层源码剖析—扫描1.1、Spring底层扫描机制doScan方法源码剖析 一、Spring生命周期核心底层源码剖析—扫描 1.1、Spring底层扫描机制doScan方法源码剖析 其源代码如下: protected Set<BeanDefinitionHolder> doScan(Strin…...
关于Thread.sleep方法的一些使用
Thread.sleep方法的作用就是使当前线程暂停执行一段指定的时间。 它的参数是以ms为单位的时间参数,表示暂停时间长度。如Thread.sleep(1000);表示暂停1s。 这个方法通常用在以下一些情况: 1、模拟延迟:在某些情况下,我们希望在…...
MeterSphere | 前端入参加密
项目场景: 在 MeterSphere 开源框架中,解决前端手机号入参加密 解决方案: 导入 JavaScript 包采用加密算法 导入网上 JavaScript 包 // 1. 通过cdn加载网上的js文件 g new Packages.org.mozilla.javascript.tools.shell.Global(Packages.o…...
微服务如何做负载均衡?
笔者在参与联通某子公司时,遇到了这样一个问题。感觉比较实际,特来记录一波。 先看腾讯混元的解答: 微服务架构中,负载均衡是必不可少的。在微服务中,负载均衡可以通过以下几种方式来实现: 1. DNS轮询&am…...
C++高级编程:构建高效稳定接口与深入对象设计技巧
C高级编程:构建高效稳定接口与深入对象设计技巧 建立稳定接口 类是C中的主要抽象单位。你应该将抽象原则应用于你的类,尽可能将接口与实现分离。具体来说,你应该使所有数据成员私有,并可选择性地提供getter和setter方法。这就是…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...