Java面向对象与多态
目录
Java面向对象与多态
多态介绍
形成多态的前提
多态下成员访问的特点
成员变量
成员方法
访问特点总结
多态对比普通继承
普通继承优点与缺点
多态优点与缺点
向上转型与向下转型
向下转型存在的问题
多态+接口练习
Java面向对象与多态
多态介绍
在前面学习到的接口和继承中,如果父类只能使用父类的方法,子类可以使用父类和自己的方法,但是有时需要使用父类调用子类重写的父类方法,上面的思路就不再合适,此时就可以使用多态。
多态的特点:使用父类引用指向子类的对象,此时父类可以调用子类重写父类的方法,但是调不到子类特有的成员
形成多态的前提
使用多态需要保证四点:
- 保证存在继承(包括接口与实现类)关系
- 子类重写了父类中非私有的方法
- 父类引用指向子类对象
- 父类引用调用子类重写的父类方法
例如下面的代码:
// 父类
public abstract class Base {public abstract void method();
}// 子类
public class Derived extends Base{// 重写父类的抽象方法@Overridepublic void method() {System.out.println("子类重写父类的方法");}
}// 测试
public class Test {public static void main(String[] args) {// 父类引用指向子类对象Base base = new Derived();base.method();// 调用重写的方法}
}
多态下成员访问的特点
成员变量
实现多态后,因为是父类引用,所以只能访问到子类与父类共用的成员
// 父类
public abstract class Base {// 父类成员public int numBase;public Base(int numBase) {this.numBase = numBase;}
}// 子类
public class Derived extends Base{public int numDerived;public Derived(int numBase, int numDerived) {super(numBase);this.numDerived = numDerived;}
}// 测试
public class Test {public static void main(String[] args) {// 父类引用指向子类对象Base base = new Derived(10, 20);System.out.println(base.numBase);// 访问父类属性
// System.out.println(base.numDeried); // 无法访问子类属性}
}
成员方法
多态出现的意义就是父类引用可以访问到子类的方法,但是只能访问到子类重写的父类方法
// 父类
public abstract class Base {public abstract void method();
}// 子类
public class Derived extends Base{// 重写父类的抽象方法@Overridepublic void method() {System.out.println("子类重写父类的方法");}// 子类特有方法public void methodDerived(){System.out.println("子类特有方法");}
}// 测试
public class Test {public static void main(String[] args) {// 父类引用指向子类对象Base base = new Derived(10, 20);base.method();// 调用重写的方法
// base.methodDerived(); // 无法访问子类特有方法}
}
访问特点总结
- 访问成员变量时:看赋值符号左侧是子类还是父类,如果是父类,调用就是父类成员变量,否则调用的是子类成员变量
- 访问成员方法时:看
new
的是哪一个对象,如果是子类,则访问的是子类中的成员方法(多态时访问的子类重写后的成员方法),否则访问的就是父类自己的成员方法
多态对比普通继承
普通继承优点与缺点
- 普通继承优点:
赋值符号左右两边类型相等,调用时父类只能访问自己的成员,子类可以访问和父类共有的成员以及自己特有的成员
- 普通继承的缺点:
可扩展性差
例如下面的代码:
// 父类
public abstract class Base {public abstract void methodBase();
}// 子类1
public class Derived1 extends Base{@Overridepublic void methodBase() {System.out.println("Derived1重写父类方法");}
}// 子类2
public class Derived2 extends Base{@Overridepublic void methodBase() {System.out.println("Derived2重写父类的方法");}
}
在普通的继承中,当子类想调用自己重写后的方法需要按照下面的方式进行:
public class Test {public static void main(String[] args) {Derived1 derived1 = new Derived1();Derived2 derived2 = new Derived2();// 调用重写的方法derived1.methodBase();derived2.methodBase();}
}
如果此时需要将两个对象作为函数的参数,就需要写两个函数,例如:
// 测试
public static void test(Derived1 derived1)
{derived1.methodBase();
}public static void test(Derived2 derived2)
{derived2.methodBase();
}
如果子类非常多,则需要覆盖的测试函数就会变多,从而导致可扩展性差
多态优点与缺点
- 多态优点:
因为父类可以访问到子类重写的方法,所以只需要在测试参数处写为父类引用即可,可扩展性强
- 多态缺点:
因为创建的是子类对象,所以只能访问子类和父类共有的成员以及子类重写父类的方法
实际上,多态出现的目的就是为了解决前面普通继承的缺点,所以多态自身的缺点可以忽略
例如,上面的测试代码就可以修改为:
public class Test {public static void main(String[] args) {Derived1 derived1 = new Derived1();Derived2 derived2 = new Derived2();test(derived1);test(derived2);}// 测试public static void test(Base base){base.methodBase();}
}
此时因为参数的base
是父类引用,而接收到的实参指向子类引用,所以实参传递给形参即父类引用指向子类引用
向上转型与向下转型
向上转型:父类引用指向子类对象,即多态
向下转型:指向子类对象的父类引用转换为子类引用,向下转型可以解决部分情况下需要调用子类特有的成员,使用强制转换的方式可以实现向下转型,例如下面的代码:
public class Test {public static void main(String[] args) {// 向上转型Base base = new Derived1();base.methodBase();// 向下转型Derived1 derived1 = (Derived1) base;derived1.methodDerived1(); // 调用子类特有的方法derived1.methodBase(); // 调用父类的方法}
}
向下转型存在的问题
向下转型之前的引用是父类引用,此时给对应的子类引用没有任何问题。但是如果给另一个子类就会出现ClassCastException
例如下面的代码,先展示正常情况下的向上转型:
// 父类
public abstract class Base {public abstract void methodBase();
}// 子类1
public class Derived1 extends Base{@Overridepublic void methodBase() {System.out.println("Derived1重写父类方法");}// 子类特有方法public void methodDerived1() {System.out.println("Derived1特有方法");}
}// 子类2
public class Derived2 extends Base{@Overridepublic void methodBase() {System.out.println("Derived2重写父类的方法");}// 子类特有方法public void methodDerived2() {System.out.println("Derived2特有方法");}
}// 测试
public class Test {public static void main(String[] args) {Base base1 = new Derived1();Base base2 = new Derived2();// 向上转型test(base1);test(base2);}public static void test(Base base){base.methodBase();}
}
接着展示向下转型:
public static void test(Base base)
{// 向下转型Derived1 derived1 = (Derived1) base;derived1.methodDerived1(); // 调用子类特有的方法
}
上面的代码当base
接收的是Derive1
的对象,则没有任何问题,因为引用也是Derive1
类的引用,但是如果base
是Derive2
的对象,此时就会出现异常,下面是报错信息:
Exception in thread "main" java.lang.ClassCastException: com.epsda.advanced.cmp_extends_polymorphic.Derived2 cannot be cast to com.epsda.advanced.cmp_extends_polymorphic.Derived1at com.epsda.advanced.cmp_extends_polymorphic.Test.test(Test.java:33)at com.epsda.advanced.cmp_extends_polymorphic.Test.main(Test.java:17)
所以,为了避免出现这种问题,再进行向下转型前需要先判断当前类型是否与引用类型匹配,可以使用instanceof
关键字,使用方式如下:
对象 instanceof 目标类
所以上面的测试代码可以修改为:
public static void test(Base base)
{// 向下转型+判断if(base instanceof Derived1) {Derived1 derived1 = (Derived1) base;derived1.methodDerived1(); // 调用子类特有的方法}else {Derived2 derived2 = (Derived2) base;derived2.methodDerived2(); // 调用子类特有的方法}
}
多态+接口练习
案例:
定义笔记本类,具备开机,关机和使用USB设备的功能。具体是什么USB设备,笔记本并不关心,只要符合USB规格的设备都可以。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,不然鼠标和键盘的生产出来无法使用
进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
- USB接口,包含开启功能、关闭功能
- 笔记本类,包含运行功能、关机功能、使用USB设备功能
- 鼠标类,要符合USB接口
- 键盘类,要符合USB接口
参考代码:
// 笔记本类
public class Laptop{// 开机方法public void startCom() {System.out.println("笔记本开机");}// 关机方法public void shutdownCom() {System.out.println("笔记本关机");}public void setUsbStart(USB usb) {usb.startUSB();}public void setUsbShutdown(USB usb) {usb.shutdownUSB();}
}// USB接口
public interface USB {// USB开机public abstract void startUSB();// USB关机public abstract void shutdownUSB();
}// 鼠标类
public class Mouse implements USB{@Overridepublic void startUSB() {System.out.println("鼠标插上");}@Overridepublic void shutdownUSB() {System.out.println("鼠标拔下");}
}// 键盘类
public class Keyboard implements USB{@Overridepublic void startUSB() {System.out.println("键盘插上");}@Overridepublic void shutdownUSB() {System.out.println("键盘拔下");}
}// 测试类
public class Test {public static void main(String[] args) {USB mouse = new Mouse();USB keyboard = new Keyboard();Laptop laptop = new Laptop();laptop.startCom();laptop.setUsbStart(mouse);laptop.setUsbStart(keyboard);laptop.setUsbShutdown(mouse);laptop.setUsbShutdown(keyboard);laptop.shutdownCom();}
}输出结果:
笔记本开机
鼠标插上
键盘插上
鼠标拔下
键盘拔下
笔记本关机
相关文章:

Java面向对象与多态
目录 Java面向对象与多态 多态介绍 形成多态的前提 多态下成员访问的特点 成员变量 成员方法 访问特点总结 多态对比普通继承 普通继承优点与缺点 多态优点与缺点 向上转型与向下转型 向下转型存在的问题 多态接口练习 Java面向对象与多态 多态介绍 在前面学习到…...

redis分布式锁和lua脚本
业务场景:多个线程对共同资源的访问:库存超卖/用户重复下单的原因 解决方法一:利用jvm内置锁,将非原子性操作变成原子性操作 Synchronized锁的是对象,对象必须是单例的。锁的是this,代表当前所在的类,这个…...

项目实战 ---- 商用落地视频搜索系统(5)---service层核心
目录 背景 向下service 层 描述 功能 代码实现 核心阐述 向上service层 描述 功能 代码实现 核心阐述 背景 之前的 1-4 重点在介绍系统的实现架构,录入数据的组织形式,存储模式,search 方式,以及后期算法等。重点都是聚焦在后端。现在来看,基本的后端实现我们…...

Win32远线程注入
远线程注入 远线程(RemoteThread)注入是指一个进程在另一个进程中创建线程的技术,这是一种很经典的DLL注入技术。 虽然比较古老,但是很实用。通过远线程注入,再配合api函数的hook技术,可以实现很多有意思的功能。 实现远线程注入…...

CTF 竞赛密码学方向学习路径规划
目录 计算机科学基础计算机科学概念的引入、兴趣的引导开发环境的配置与常用工具的安装Watt Toolkit(Steam)、机场代理Scoop(Windows 用户可选)常用 Python 库SageMathLinux小工具 yafuOpenSSL Markdown编程基础Python其他编程语言…...

2024数学建模国赛B题代码
B题已经完成模型代码!详情查看文末名片 问题1:可以考虑使用统计学中的“样本量估算”方法,使用二项分布或正态近似来决定最少的样本量,并通过假设检验(如单侧检验)在95%和90%置信度下进行判断。 import n…...

PyTorch 卷积层详解
PyTorch 卷积层详解 卷积层(Convolutional Layers)是深度学习中用于提取输入数据特征的重要组件,特别适用于处理图像和序列数据。PyTorch 提供了多种卷积层,分别适用于不同维度的数据。本文将详细介绍这些卷积层,特别…...

【Kubernetes知识点问答题】kubernetes 控制器
目录 1. 说明 K8s 控制器的作用? 2. 什么是 ReplicaSet,说明它的主要用途。 3. Deployment 控制器是如何工作的,举例说明其常见用途。 4. 解释 DaemonSet,列举其使用场景。 5. 什么是 StatefulSet,其主要作用是什么…...

Patlibc———更快捷的更换libc
起初是为了简化做pwn题目时,来回更换libc的麻烦,为了简化命令,弄了一个小脚本,可以加入到/usr/local/bin中,当作一个快捷指令🔢 这个写在了tools库(git clone https://github.com/CH13hh/tools…...

基于飞腾平台的Hive的安装配置
【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…...

c# json使用
安装包 用NuGet安装包:Newtonsoft.Json 对象转为Json字符串 public class Person {public string Name { get; set; }public int Age { get; set; } }Person person new Person { Name "John Doe", Age 30 }; string json2 JsonConvert.SerializeO…...

单点登录:cas单点登录实现原理浅析
cas单点登录实现原理浅析 一晃几个月没写博客了,今年多灾多难的一年。 安能摧眉折腰事权贵,使我不得开心颜! 财富是对认知的补偿,不是对勤奋的嘉奖。勤奋只能解决温饱,要挣到钱就得预知风口,或者有独到见解…...

java报错
java.lang.RuntimeException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.tengzhi.base.model.E_xt_xmda...

uniapp动态页面API
目录 uni.setNavigationBarTitle动态设置标题 uni.showNavigationBarLoading为标题添加加载动画与uni.hideNavigationBarLoading停止加载动画 编辑 uni.setNavigationBarColor用于设置导航栏的颜色,包括背景颜色和文字颜色。这对于自定义应用的主题和风格非常有…...

最优化方法Python计算:求解约束优化问题的拉格朗日乘子算法
从仅有等式约束的问题入手。设优化问题(7.8) { minimize f ( x ) s.t. h ( x ) o ( 1 ) \begin{cases} \text{minimize}\quad\quad f(\boldsymbol{x})\\ \text{s.t.}\quad\quad\quad \boldsymbol{h}(\boldsymbol{x})\boldsymbol{o} \end{cases}\quad\quad(1) {minimizef(x)s.…...

每日OJ_牛客_骆驼命名法(递归深搜)
目录 牛客_骆驼命名法(简单模拟) 解析代码 牛客_骆驼命名法(简单模拟) 骆驼命名法__牛客网 解析代码 首先一个字符一个字符的读取内容: 遇到 _ 就直接跳过。如果上一个字符是 _ 则下一个字符转大写字母。 #inclu…...

MySQL 数据库管理与操作指南
文章目录 MySQL 数据库管理与操作指南1. 忘记 MySQL 密码的处理方法2. MySQL 数据库备份与恢复2.1 数据库备份2.2 数据库恢复 3. MySQL 用户与权限管理3.1 创建用户与授权3.2 查看所有用户3.3 删除用户 4. 关闭 GTID 复制模式5. 查看数据表的存储引擎5.1 查看 MySQL 支持的存储…...

Android Manifest 权限描述大全对照表
115工具网(115工具网-一个提供高效、实用、方便的在线工具集合网站)提供Android Manifest 权限描述大全对照表,可以方便andriod开发者查看安卓权限描述功能 权限名称描述android.permission.ACCESS_CHECKIN_PROPERTIES访问登记属性读取或写入…...

Ollama Qwen2 支持 Function Calling
默认 Ollama 中的 Qwen2 模型不支持 Function Calling,使用默认 Qwen2,Ollama 会报错。本文将根据官方模板对 ChatTemplate 进行改进,使得Qwen2 支持 Tools,支持函数调用。 Ollama 会检查对话模板中是否存在 Tools,如…...

APP测试工程师岗位面试题
一、你们公司研发团队采用敏捷开发模式的原因? 由于版本节奏比较快,开发与测试几乎并行,一个版本周期内会有两版在推动,也就是波次发布,波次发布用于尝试新加入的功能,做小范围快速的开发,验证…...

如何进行 AWS 云监控
什么是 AWS? Amazon Web Services(AWS)是 Amazon 提供的一个全面、广泛使用的云计算平台。它提供广泛的云服务,包括计算能力、存储选项、网络功能、数据库、分析、机器学习、人工智能、物联网和安全。 使用 AWS 有哪些好处&…...

第十六篇:走入计算机网络的传输层--传输层概述
1. 传输层的功能 ① 分割与重组数据 一次数据传输有大小限制,传输层需要做数据分割,所以在数据送达后必然也需要做数据重组。 ② 按端口号寻址 IP只能定位数据哪台主机,无法判断数据报文应该交给哪个应用,传输层给每个应用都设…...

提升效率!ArcGIS中创建脚本工具
在我们日常使用的ArcGIS中已经自带了很多功能强大的工具,但有时候遇到个人的特殊情况还是无法满足,这时就可以试着创建自定义脚本工具。 一、编写代码 此处的代码就是一个很简单的给图层更改别名的代码。 1. import arcpy 2. input_fc arcpy.GetParam…...

无人机之报警器的作用
一、紧急救援与辅助搜救 紧急救援:在事故或紧急情况下,无人机报警器可以迅速发出警报,指引救援人员前往事故地点,提高救援效率。 辅助搜救:无人机搭载报警器可以辅助寻找失踪人员或其他需要搜救的场景,通…...

风格控制水平创新高!南理工InstantX小红书发布CSGO:简单高效的端到端风格迁移框架
论文链接:https://arxiv.org/pdf/2408.16766 项目链接:https://csgo-gen.github.io/ 亮点直击 构建了一个专门用于风格迁移的数据集设计了一个简单但有效的端到端训练的风格迁移框架CSGO框架,以验证这个大规模数据集在风格迁移中的有益效果。…...

python文件自动化(4)
接上节课内容,在开始正式移动文件到目标文件夹之前,我们需要再思考一个问题。在代码运行之前,阿文的下载文件夹里已经存在一些分类文件夹了,比如图例中“PDF文件”这个文件夹就是已经存在的。这样的话,在程序运行时&am…...

HTTP 方法
HTTP 方法 1. 引言 HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的协议之一。它定义了客户端和服务器之间交换信息的格式和规则。在HTTP通信中,客户端(通常是浏览器)向服务器…...

通过redis-operator 来部署 Redis Cluster 集群
安装 Redis Operator 首先,需要安装 redis-operator。可以通过 Helm 或直接应用 YAML 文件来安装。 使用 Helm 安装: helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/ helm install redis-operator ot-helm/redis-operator --…...

vue3集成sql语句编辑器
使用的是codemirror 安装 pnpm add codemirror vue-codemirror --savepnpm add codemirror/lang-sqlpnpm add codemirror/theme-one-dark使用 <template><codemirror v-model"configSql" placeholder"Code goes here..." ref"codemirrorR…...

Optuna发布 4.0 重大更新:多目标TPESampler自动化超参数优化速度提升显著
Optuna这个备受欢迎的超参数优化框架在近期发布了其第四个主要版本。自2018年首次亮相以来,Optuna不断发展,现已成为机器学习领域的重要工具。其用户社区持续壮大,目前已达到以下里程碑: 10,000 GitHub星标每月300万 下载量16,00…...