JavaSE学习进阶day03_01 多态

news2025/1/19 17:07:37

第一章 多态

1.1 多态的形式

直接说什么是多态性太抽象了,我们先引入一个例子:

现在我定义了一个feed方法,在不同的类的对象调用这个方法时,都要改变形参,即每当我的对象不同时,都要重载该方法,这显然是很费时间,也不方便的,这时候就引入多态的概念。在这里我们可以认为形参既能接受猫的对象,也能接受狗的对象。因为猫和狗都是动物类的子类。

多态:同一个对象,在不同时刻表现出来的不同形态。

多态的几点细节:

父类引用指向子类对象:

父类 父类对象名 = 子类 子类对象名

多态是继封装、继承之后,面向对象的第三大特性。

多态是出现在继承或者实现关系中的

多态体现的格式

父类类型 变量名 = new 子类/实现类构造器;
变量名.方法名();

多态的前提:有继承关系,子类对象是可以赋值给父类类型的变量。例如Animal是一个动物类型,而Cat是一个猫类型。Cat继承了Animal,Cat对象也是Animal类型,自然可以赋值给父类类型的变量。

1.2 多态的案例演示

当使用多态方式调用成员变量时,首先检查父类中是否有该成员变量,如果没有,则编译错误;如果有,则执行的是父类里的成员变量

总结起来就是:编译看左边,运行看左边。

理解比较困难,直接看代码演示:

创建一个父类,创建一个子类,让子类继承父类,现在实现多态,就是让父类引用指向子类对象。即Fu fu=new Zi(),现在打印父类引用的成员变量,发现打印的是父类的成员变量,这就是执行看左边,也就是说执行的是父类的成员变量。那么什么是编译看左边呢?如果我们把父类的成员变量name注释掉。如下:

发现已经出现错误了,原来编译看左边的意思就是说在编译的时候左边的父类里必须得有name这个成员变量,如果没有就会报错。

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。如果子类没有重写该方法,就会调用父类的该方法。(也就是调用子类的方法时,父类必须有该相同的方法)

总结起来就是:编译看左边,运行看右边

直接看代码:

意思同上,执行看右边就是说,执行的是右边子类的方法。如果把父类的该方法注释掉,会报错如下,这也就是编译看左边的意思。

说白了就是子类的所有方法,在父类中也得全部有,但这显然是不可能的,这也就是多态的弊端:不能使用子类特有的功能!!(后面的转型可以解决该问题)

注意,在多态中,不管是成员变量还是成员方法,父类中一定得有,否则编译报错。至于对成员方法执行看右边,当子类没有重写该成员方法时,就执行相应父类的方法。子类可以没有该方法,但是父类必须得有。

再看一个练习:

定义父类:

public class Animal {
    public void eat() {
        System.out.println("动物吃东西!");
    }
}

定义子类:

class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
}  
​
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
}

定义测试类:

public class Test {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Animal a1 = new Cat();
        // 调用的是 Cat 的 eat
        a1.eat();
​
        // 多态形式,创建对象
        Animal a2 = new Dog();
        // 调用的是 Dog 的 eat
        a2.eat();
    }  
}

回想文章最开始那个问题,现在就可以用多态来解决了:

1.3 多态的定义和前提

多态: 是指同一行为,具有多个不同表现形式。

从上面案例可以看出,Cat和Dog都是动物,都是吃这一行为,但是出现的效果(表现形式)是不一样的。

前提【重点】

  1. 有继承或者实现关系

  2. 方法的重写【意义体现:不重写,无意义】

  3. 父类引用指向子类对象【格式体现】

  4. 父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

当一个方法既然接收A类的对象,又要接收B类的对象。如果A和B又有共同的父类,方法的形参可以写父类类型。 此时方法中,会根据传递过来的对象,动态的调用不同子类中的方法。

1.4 多态的好处

实际开发的过程中:

1,方法的形参是一个非抽象类时,在调用方法时,可以传递父类对象,可以传递所有的子类对象。

2,方法的形参是一个抽象类时,在调用方法时,可以传递所有的子类对象。

3,方法的形参是一个接口时,在调用方法时,可以传递所有的实现类对象。

看一个案例:

定义父类:

public abstract class Animal {  
    public abstract void eat();  
}  

定义子类:

class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
}  
​
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
}

定义测试类:

public class Test {
    public static void main(String[] args) {
        // 多态形式,创建对象
        Cat c = new Cat();  
        Dog d = new Dog(); 
​
        // 调用showCatEat 
        showCatEat(c);
        // 调用showDogEat 
        showDogEat(d); 
​
        /*
        以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
        而执行效果一致
        */
        showAnimalEat(c);
        showAnimalEat(d); 
    }
​
    public static void showCatEat (Cat c){
        c.eat(); 
    }
​
    public static void showDogEat (Dog d){
        d.eat();
    }
​
    public static void showAnimalEat (Animal a){
        a.eat();
    }
}

由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当然可以把Cat对象和Dog对象,传递给方法。

当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致,所以showAnimalEat完全可以替代以上两方法。

不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用showAnimalEat都可以完成。从而实现了实现类的自动切换。

所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。

注意多态的引入不是说让你以后创建对象都要让父类对象指向子类对象,而是作为形参用来进行传递参数的,搞懂上面那个练习我想就能搞懂多态的作用

1.5 多态的运行特点

调用成员变量时:编译看左边,运行看左边

调用成员方法时:编译看左边,运行看右边

代码示例:

Fu f = new Zi();
//编译看左边的父类中有没有name这个属性,没有就报错
//在实际运行的时候,把父类name属性的值打印出来
System.out.println(f.name);
//编译看左边的父类中有没有show这个方法,没有就报错
//在实际运行的时候,运行的是子类中的show方法,如果子类没有重写该方法则执行父类的该方法
f.show();

1.6 多态的弊端

我们已经知道多态编译阶段是看左边父类类型的,如果子类有些独有的功能,此时多态的写法就无法访问子类独有功能了。除非父类有子类的全部方法,(这显然是不可能的),否则会编译报错。

看一个案例:

class Animal{
    public  void eat(){
        System.out.println("动物吃东西!")
    }
}
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
   
    public void catchMouse() {  
        System.out.println("抓老鼠");  
    }  
}  
​
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
}
​
class Test{
    public static void main(String[] args){
        Animal a = new Cat();
        a.eat();
        a.catchMouse();//编译报错,编译看左边,Animal没有这个方法,
        //不能使用子类特有的方法。
    }
}

1.7 引用类型转换

1.7.1 为什么要转型

多态的弊端就是无法访问子类特有功能怎么解决这个问题?就需要转型。

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

回顾基本数据类型转换

  • 自动转换: 范围小的赋值给范围大的.自动完成:double d = 5;

  • 强制转换: 范围大的赋值给范围小的,强制转换:int i = (int)3.14

多态的转型分为向上转型(自动转换)与向下转型(强制转换)两种。

1.7.2 向上转型(自动转换)

  • 向上转型(从子到父):多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式:

父类类型  变量名 = new 子类类型();
如:Animal a = new Cat();

原因是:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。

1.7.3 向下转型(强制转换)

  • 向下转型(从父到子):父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:

子类类型 变量名 = (子类类型) 父类变量名;
如:Aniaml a = new Cat();
   Cat c =(Cat) a;  

1.7.4 案例演示

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法,即子类特有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型

转型演示,代码如下:

定义类:

abstract class Animal {  
    abstract void eat();  
}  
​
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void catchMouse() {  
        System.out.println("抓老鼠");  
    }  
}  
​
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void watchHouse() {  
        System.out.println("看家");  
    }  
}

定义测试类:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();                // 调用的是 Cat 的 eat
​
        // 向下转型  
        Cat c = (Cat)a;   //向下转型后就可以调用子类特有的方法了    
        c.catchMouse();         // 调用的是 Cat 的 catchMouse
    }  
}

1.7.5 转型的异常

转型的过程中,一不小心就会遇到这样的问题,请看如下代码:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat
​
        // 向下转型  
        Dog d = (Dog)a;       
        d.watchHouse();        // 调用的是 Dog 的 watchHouse 【运行报错】
    }  
}

这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。

1.7.6 instanceof关键字(必须掌握!)

为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

变量名 instanceof 数据类型 
如果变量属于该数据类型或者其子类类型,返回true。
如果变量不属于该数据类型或者其子类类型,返回false。

所以,转换前,我们最好先做一个判断,代码如下:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat
​
        // 向下转型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 调用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 调用的是 Dog 的 watchHouse
        }
    }  
}

多态的总结:

注意:就是那个父类可以是爷爷类,甚至更高一层的类,当然他们也统称为父类。

注意(超级重点!!):1、当接口作为形参时,所有实现这个接口的类的对象都可以作为实参进行传递!这个是本节的一个重点。

2、.当一个方法的形参是一个类,那么我们可以传递这个类的对象和这个类所有的子类对象

3、当一个方法的形参是一个抽象类,可以传递这个类所有的子类对象

多态的内存(了解,科班出身的最好理解)

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

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

相关文章

【Java基础】day13

day13 一、Spring Bean 生命周期是怎样的? 详细过程分为以下几个步骤: ① 初始化 Bean 容器通过获取 BeanDefinition 中的信息进行实例化,这一步仅仅是简单的实例化,并没有进行依赖注入。 实例化的对象被包装在 BeanWrapper 对…

Qt音视频开发38-ffmpeg视频暂停录制的设计

一、前言 基本上各种播放器提供的录制视频接口,都是只有开始录制和结束录制两个,当然一般用的最多的也是这两个接口,但是实际使用过程中,还有一种可能需要中途暂停录制,暂停以后再次继续录制,将中间部分视…

RabbitMq架构设计原理

文章目录1、消息中间件1.1、什么是消息中间件1.2、传统的HTTP请求有什么缺点1.3、MQ的应用场景2、同步、多线程、以及MQ处理业务逻辑的区别2.1、同步发送Http 请求2.2、多线程处理业务逻辑2.3、MQ实现业务逻辑Mq和多线程之间的区别3、Mq消息中间件名词4、简单实现Mq的思路4.1、…

MySQL索引15连问,你能坚持到第几问?

目录 1.索引是什么? 2.MySQL索引有哪些类型 3.索引什么时候会失效? 4.哪些场景不适合建立索引? 5.为什么要用 B树,为什么不用二叉树? 6.一次B树索引树查找过程 7.什么是回表? 如何减少回表? 8.什么是覆盖索引? 9.聊聊索引的最左前缀原则 10.索引下…

Phind——一款面向开发人员的AI搜索引擎

目录前言一、Phind优点二、使用方法总结前言 Phind是一款面向开发人员的AI搜索引擎,它由大语言模型(Large Language Model,LLM)驱动 。相比于传统的搜索引擎,Phind有以下优势:自然语言搜索、面向开发者、AI…

【数据结构】期中考试一把梭(通宵版上)

前言 红中(Hong_zhong) CSDN内容合伙人、2023年新星计划web安全方向导师、 吉林师范大学网安大一的一名普通学生、摸鱼拿过大挑校二、 华为MindSpore截至目前最年轻的优秀开发者、IK&N战队队长、 阿里云专家博主、华为网络安全云享专家、腾讯云自媒体分享计划博主、 划了…

URL 和 HandlerMapping建立映射(11)

上一篇https://blog.csdn.net/chen_yao_kerr/article/details/130194864 我们已经分析了Spring MVC的配置,并且说明了如何通过注解的方式去替换各种各样的xml配置文件。本篇将更深入分析: 取代 springmvc.xml 配置 之前我们说过,定义一个类…

简述API(电商数据API)网关的概念和功能

API 网关 ( API gateway ) 前言 在 IOT ( 物联网 )中,当我们的一些设备。例如( 监控、传感器等 )需要将收集到的数据和信息进行汇总时,我们就需要一个 API。(如果你需要Taobao/JD/pinduoduo平台…

OpenAI-ChatGPT最新官方接口《语音智能转文本》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(六)(附源码)

Speech to text 语音智能转文本Introduction 导言Quickstart 快速开始Transcriptions 转录python代码cURL代码Translations 翻译python代码cURL代码Supported languages 支持的语言Longer inputs 长文件输入Prompting 提示其它资料下载Speech to text 语音转文本 Learn how to …

一句话设计模式11:过滤器模式

过滤器模式: 直接看 java8的filter; 文章目录过滤器模式: 直接看 java8的filter;前言一、过滤器模式的作用二、如何实现过滤器模式直接上代码总结前言 过滤器模式一般使用场景是: 过滤集合中的不同元素的一种手段,其实平时开发中你经常用,但是你不知道而已;(心里话: 这也算一种…

C++命名空间

C命名空间 C命名空间是一种用于组织代码的机制,它可以将全局命名空间划分为更小的、独立的部分,从而避免命名冲突和名字空间污染。在本文中,我们将介绍C命名空间的基本概念、使用方法和注意事项。 什么是命名空间? 命名空间是C…

QT

多平台C图形用户界面应用程序框架 集成了很多可以直接运用的图形的库 应用在windowns10系统 新建项目 有三种基类可以选择,开发是基于这三种基类的基础上,利用软件支持的QT语言进行界面元素添加与优化 代码添加(添加代码时,大小…

flutter实战(1)-配置安装

目录支持的OS安装SDKwindows找到windows对应的SDK安装LINUXsnapd手动IDEMacLinux 或者 Windows 平台支持的OS 有以下这些OS可以安装配置flutter 安装SDK windows 要想安装和运行 Flutter,你的开发环境至少应该满足如下的需求: 操作系统:W…

组合预测模型 | SSA-LSTM、LSTM麻雀算法优化长短期记忆神经网络时间序列预测(Matlab程序)

组合预测模型 | SSA-LSTM、LSTM麻雀算法优化长短期记忆神经网络时间序列预测(Matlab程序) 目录 组合预测模型 | SSA-LSTM、LSTM麻雀算法优化长短期记忆神经网络时间序列预测(Matlab程序)预测结果评价指标基本介绍程序设计参考资料预测结果 评价指标 SSA-LSTM优化得到的最优…

[TIFS 2022] FLCert:可证明安全的联邦学习免受中毒攻击

FLCert: Provably Secure Federated Learning Against Poisoning Attacks | IEEE Journals & Magazine | IEEE Xplore 摘要 由于其分布式性质,联邦学习容易受到中毒攻击,其中恶意客户端通过操纵其本地训练数据和/或发送到云服务器的本地模型更新来毒…

阿里“通义千问”大模型上线!让生成式AI更贴近中国人生活

阿里版的 ChatGPT 语言大模型来了。 张勇在峰会上表示,阿里巴巴所有产品未来将接入“通义千问”大模型,进行全面改造。他认为,面向AI时代,所有产品都值得用大模型重新升级。 目前,钉钉、天猫精灵等产品已接入通义千问测…

PYQT5学习笔记00——Pycharm环境搭建以及配置项目虚拟环境教程

1、安装基本环境 需要的基本环境有python3.x的解释器、pip包管理工具以及pipenv虚拟环境管理工具。   我们安装了python后,pip包管理工具会自带安装,pipenv虚拟环境管理工具我们使用pycharm即可,无需使用python自带的。 python解释器下载地…

【Git代码仓库托管】上海道宁为您提供构建、扩展和交付安全软件的完整开发人员平台

GitHub是用于 构建、扩展和交付安全软件的 完整开发人员平台 通过提高开发人员速度的工具 推动创新 加快高质量软件开发 GitHub提供无限的存储库 一流的版本控制和 世界上强大的开源社区 因此您的团队可以 更高效地协同工作 开发商介绍 GitHub归属于微软公司&#xf…

Java EE企业级应用开发(SSM)第6章

第6章Spring MVC应用一.预习笔记 1.Spring MVC的请求参数 项目的基础配置 web.xml springmvc-config.xml jar包资源引入: 1-1:获取默认参数 jsp页面如下: Controller如下: 1-2:简单数据类型(获取数据不…

sqlplus / as sysdba无法登陆

dba你快用你无敌sysdba登陆数据库! 导言:as sysdba属于特殊的数据库权限,使用的是系统认证,sqlplus sys/passtns as sysdba用的才是你的密码文件中的设置 #认证设置问题 配置在sqlnet.ora文件 在linux下 #sqlnet.authenticati…