Java面向对象三大特性之多态及综合练习
1.1 多态的形式
多态是继封装、继承之后,面向对象的第三大特性。
多态是出现在继承或者实现关系中的。
多态体现的格式:
父类类型 变量名 = new 子类/实现类构造器; 变量名.方法名();
多态的前提:有继承关系,子类对象是可以赋值给父类类型的变量。例如Animal是一个动物类型,而Cat是一个猫类型。Cat继承了Animal,Cat对象也是Animal类型,自然可以赋值给父类类型的变量。
1.2 多态的使用场景
如果没有多态,在下图中register方法只能传递学生对象,其他的Teacher和administrator对象是无法传递给register方法方法的,在这种情况下,只能定义三个不同的register方法分别接收学生,老师和管理员。
有了多态之后,方法的形参就可以定义为共同的父类Person。
要注意的是:
-
当一个方法的形参是一个类,我们可以传递这个类所有的子类对象。
-
当一个方法的形参是一个接口,我们可以传递这个接口所有的实现类对象(后面会学)。
-
而且多态还可以根据传递的不同对象来调用不同类中的方法。
代码示例:
父类:
public class Person {private String name;private int age;
空参构造带全部参数的构造get和set方法
public void show(){System.out.println(name + ", " + age);}
}
子类1:
public class Administrator extends Person {@Overridepublic void show() {System.out.println("管理员的信息为:" + getName() + ", " + getAge());}
}
子类2:
public class Student extends Person{
@Overridepublic void show() {System.out.println("学生的信息为:" + getName() + ", " + getAge());}
}
子类3:
public class Teacher extends Person{
@Overridepublic void show() {System.out.println("老师的信息为:" + getName() + ", " + getAge());}
}
测试类:
public class Test {public static void main(String[] args) {//创建三个对象,并调用register方法
Student s = new Student();s.setName("张三");s.setAge(18);
Teacher t = new Teacher();t.setName("王建国");t.setAge(30);
Administrator admin = new Administrator();admin.setName("管理员");admin.setAge(35);
register(s);register(t);register(admin);
}
//这个方法既能接收老师,又能接收学生,还能接收管理员//只能把参数写成这三个类型的父类public static void register(Person p){p.show();}
}
1.3 多态的定义和前提
多态: 是指同一行为,具有多个不同表现形式。
从上面案例可以看出,Cat和Dog都是动物,都是吃这一行为,但是出现的效果(表现形式)是不一样的。
前提【重点】
-
有继承或者实现关系
-
方法的重写【意义体现:不重写,无意义】
-
父类引用指向子类对象【格式体现】
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
1.4 多态的运行特点
调用成员变量时:编译看左边,运行看左边
调用成员方法时:编译看左边,运行看右边
代码示例:
Fu f = new Zi();
//编译看左边的父类中有没有name这个属性,没有就报错
//在实际运行的时候,把父类name属性的值打印出来
System.out.println(f.name);
//编译看左边的父类中有没有show这个方法,没有就报错
//在实际运行的时候,运行的是子类中的show方法
f.show();
1.5 多态的弊端
我们已经知道多态编译阶段是看左边父类类型的,如果子类有些独有的功能,此时多态的写法就无法访问子类独有功能了。
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.6 引用类型转换
1.6.1 为什么要转型
多态的写法就无法访问子类独有功能了。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
回顾基本数据类型转换
-
自动转换: 范围小的赋值给范围大的.自动完成:double d = 5;
-
强制转换: 范围大的赋值给范围小的,强制转换:int i = (int)3.14
多态的转型分为向上转型(自动转换)与向下转型(强制转换)两种。
1.6.2 向上转型(自动转换)
-
向上转型:多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式:
父类类型 变量名 = new 子类类型(); 如:Animal a = new Cat();
原因是:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。
1.6.3 向下转型(强制转换)
-
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名; 如:Aniaml a = new Cat();Cat c =(Cat) a;
1.6.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.6.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.6.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.6.7 instanceof新特性
JDK14的时候提出了新特性,把判断和强转合并成了一行
//新特性
//先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if(a instanceof Dog d){d.lookHome();
}else if(a instanceof Cat c){c.catchMouse();
}else{System.out.println("没有这个类型,无法转换");
}
1.7 综合练习
需求:根据需求完成代码:1.定义狗类属性:年龄,颜色行为:eat(String something)(something表示吃的东西)看家lookHome方法(无参数) 2.定义猫类属性:年龄,颜色行为:eat(String something)方法(something表示吃的东西)逮老鼠catchMouse方法(无参数) 3.定义Person类//饲养员属性:姓名,年龄行为:keepPet(Dog dog,String something)方法功能:喂养宠物狗,something表示喂养的东西行为:keepPet(Cat cat,String something)方法功能:喂养宠物猫,something表示喂养的东西生成空参有参构造,set和get方法 4.定义测试类(完成以下打印效果):keepPet(Dog dog,String somethind)方法打印内容如下:年龄为30岁的老王养了一只黑颜色的2岁的狗2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃keepPet(Cat cat,String somethind)方法打印内容如下:年龄为25岁的老李养了一只灰颜色的3岁的猫3岁的灰颜色的猫眯着眼睛侧着头吃鱼 5.思考: 1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
画图分析:
代码示例:
//动物类(父类)
public class Animal {private int age;private String color;
public Animal() {}
public Animal(int age, String color) {this.age = age;this.color = color;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getColor() {return color;}
public void setColor(String color) {this.color = color;}
public void eat(String something){System.out.println("动物在吃" + something);}
}
//猫类(子类)
public class Cat extends Animal {
public Cat() {}
public Cat(int age, String color) {super(age, color);}
@Overridepublic void eat(String something) {System.out.println(getAge() + "岁的" + getColor() + "颜色的猫眯着眼睛侧着头吃" + something);}
public void catchMouse(){System.out.println("猫抓老鼠");}
}
//狗类(子类)
public class Dog extends Animal {public Dog() {}
public Dog(int age, String color) {super(age, color);}
//行为//eat(String something)(something表示吃的东西)//看家lookHome方法(无参数)@Overridepublic void eat(String something) {System.out.println(getAge() + "岁的" + getColor() + "颜色的狗两只前腿死死的抱住" + something + "猛吃");}
public void lookHome(){System.out.println("狗在看家");}
}
//饲养员类
public class Person {private String name;private int age;
public Person() {}
public Person(String name, int age) {this.name = name;this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
//饲养狗/* public void keepPet(Dog dog, String something) {System.out.println("年龄为" + age + "岁的" + name + "养了一只" + dog.getColor() + "颜色的" + dog.getAge() + "岁的狗");dog.eat(something);}
//饲养猫public void keepPet(Cat cat, String something) {System.out.println("年龄为" + age + "岁的" + name + "养了一只" + cat.getColor() + "颜色的" + cat.getAge() + "岁的猫");cat.eat(something);}*/
//想要一个方法,能接收所有的动物,包括猫,包括狗//方法的形参:可以写这些类的父类 Animalpublic void keepPet(Animal a, String something) {if(a instanceof Dog d){System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的狗");d.eat(something);}else if(a instanceof Cat c){System.out.println("年龄为" + age + "岁的" + name + "养了一只" + c.getColor() + "颜色的" + c.getAge() + "岁的猫");c.eat(something);}else{System.out.println("没有这种动物");}}
}
//测试类
public class Test {public static void main(String[] args) {//创建对象并调用方法/* Person p1 = new Person("老王",30);Dog d = new Dog(2,"黑");p1.keepPet(d,"骨头");
Person p2 = new Person("老李",25);Cat c = new Cat(3,"灰");p2.keepPet(c,"鱼");*/
//创建饲养员的对象Person p = new Person("老王",30);Dog d = new Dog(2,"黑");Cat c = new Cat(3,"灰");p.keepPet(d,"骨头");p.keepPet(c,"鱼");
}
}
相关文章:
Java面向对象三大特性之多态及综合练习
1.1 多态的形式 多态是继封装、继承之后,面向对象的第三大特性。 多态是出现在继承或者实现关系中的。 多态体现的格式: 父类类型 变量名 new 子类/实现类构造器; 变量名.方法名(); 多态的前提:有继承关系,子类对象是可以赋…...
HTTPS 握手过程
HTTPS 握手过程 HTTP 通信的缺点 通信使用明文,内容可能被窃听(重要密码泄露)不验证通信方身份,有可能遭遇伪装(跨站点请求伪造)无法证明报文的完整性,有可能已遭篡改(运营商劫持) HTTPS 握手过程 客户端发起 HTTPS 请求 用户在浏览器里…...
docker之Consul环境的部署
目录 一.Docker consul的介绍 1.1template模板(更新) 1.2registrator(自动发现) 1.3agent(代理) 二.consul的工作原理 三.Consul的特性 四.Consul的使用场景 五.搭建Consul的集群 5.1需求 5.2部署consul 5.3主服务器[192.168.40.20] 5.4client部署&…...
服务机器人,正走向星辰大海
大数据产业创新服务媒体 ——聚焦数据 改变商业 国内机器人联盟(IFR)将机器人划分为工作机器人、服务机器人、特种机器人三类。服务机器人广泛应用于餐饮场景、酒店场景,早已构成一道靓丽的风景。行业数据显示, 作为服务机器人发…...
SciencePub学术 | 计算机及交叉类重点SCIE征稿中
SciencePub学术 刊源推荐: 计算机及交叉类重点SCIE征稿中!信息如下,录满为止: 一、期刊概况: 计算机土地类重点SCIE 【期刊简介】IF:1.0-1.5,JCR4区,中科院4区; 【版面类型】正刊…...
Java面试题--SpringCloud篇
一、Spring Cloud 1. 什么是微服务架构? 微服务架构就是将单体的应用程序分成多 个应用程序,这多个应用程序就成为微服 务,每个微服务运行在自己的进程中,并 使用轻量级的机制通信 这些服务围绕业务能力来分,并通过自…...
【linux】常用的互斥手段及实例简述
文章目录 10. 原子变量(atomic_t)20. 自旋锁(spinlock_t)21. 读写锁(rwlock_t)22. 顺序锁(seqlock_t) 10. 原子变量(atomic_t) 头文件 #include <linux/types.h> // -> <linuc/atomic.h> // -> <asm-generic/atomic64.h>结构体 /* 32bit */ typedef …...
STM32 F103C8T6学习笔记12:红外遥控—红外解码-位带操作
今日学习一下红外遥控的解码使用,红外遥控在日常生活必不可少,它的解码与使用也是学习单片机的一个小过程,我们将通过实践来实现它。 文章提供源码、测试工程下载、测试效果图。 目录 红外遥控原理: 红外遥控特点: …...
linux 环境收集core文件步骤
Linux环境下进程发生异常而挂掉,通常很难查找原因,但是一般Linux内核给我们提供的核心文件,记录了进程在崩溃时候的信息,在C语言类的大型项目中,有助于深入定位。其配置流程如下: 1 查看生成core文件开关是…...
Git企业开发控制理论和实操-从入门到深入(一)|为什么需要Git|Git的安装
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总https://blog.csdn.net/yu_cblog/cate…...
上篇——税收大数据应用研究
财税是国家治理的基础和重要支柱,税收是国家治理体系的重要组成部分。我们如何利用税收数据深入挖掘包含的数据价值,在进行数据分析,提升税收治理效能,推进税收现代化。 1. 定义与特点 对于“大数据”(Big data&#…...
疲劳驾驶检测和识别4:C++实现疲劳驾驶检测和识别(含源码,可实时检测)
疲劳驾驶检测和识别4:C实现疲劳驾驶检测和识别(含源码,可实时检测) 目录 疲劳驾驶检测和识别4:C实现疲劳驾驶检测和识别(含源码,可实时检测) 1.疲劳驾驶检测和识别方法 2.人脸检测方法 3.疲劳驾驶识别模型(Python) …...
Android WakefulBroadcastReceiver的使用
WakefulBroadcastReceiver 是一种特殊类型的广播接收器,为应用创建和管理 PARTIAL_WAKE_LOCK 。 简单来说, WakefulBroadcastReceiver 是持有系统唤醒锁的 BroadcastReceiver ,用于执行需要保持CPU运转的场景。 注册 注册 Receiver &#…...
python知识:什么是字符编码?
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 我们的MySQL使用latin1的默认字符集, 也就是说,对汉字字段直接使用GBK内码的编码进行存储, 当需要对一些有汉字的字段进行拼音排序时(特别涉及到类似于名字这样的字段时…...
Vue2中使用Pinia
Vue2中使用Pinia 1.初始化配置 # main.jsimport Vue from vue import App from ./App.vue import pinia from ./stores/index import { PiniaVuePlugin } from piniaVue.use(PiniaVuePlugin)new Vue({render: h > h(App),pinia, }).$mount(#app)2.模块化开发 新建stores文…...
Docker关于下载,镜像配置,容器启动,停止,查看等基础操作
系列文章目录 文章目录 系列文章目录前言一、安装Docker并配置镜像加速器二、下载系统镜像(Ubuntu、 centos)三、基于下载的镜像创建两个容器 (容器名一个为自己名字全拼,一个为首名字字母)四、容器的启动、 停止及重启…...
穿越网络迷雾的神奇通道 - WebSocket详解
WebSocket,作为一项前端技术,已经成为现代Web应用不可或缺的一部分。本文将深入解析WebSocket,介绍其工作原理和用途,并通过简单的代码示例,让你对这个神奇的网络通信协议有更深入的了解。 WebSocket是什么࿱…...
无脑入门pytorch系列(五)—— nn.Dropout
本系列教程适用于没有任何pytorch的同学(简单的python语法还是要的),从代码的表层出发挖掘代码的深层含义,理解具体的意思和内涵。pytorch的很多函数看着非常简单,但是其中包含了很多内容,不了解其中的意思…...
Python土力学与基础工程计算.PDF-压水试验
Python 求解代码如下: 1. import math 2. 3. # 输入参数 4. L 2.0 # 试验段长度,m 5. Q 120.0 # 第三阶段计算流量,L/min 6. p 1.5 # 第三阶段试验段压力,MPa 7. r0 0.05 # 钻孔半径,m 8. 9. # 计算透…...
Linux入门
一、安装相关软件 1.下载vmware (很容易下载,搜一下官网 ) 在cmd敲入 ncpa.cpl ,查看是否有vmware 2.下载centos 下面是镜像源网站,当然你可以选择其他的镜像源,像清华镜像源和阿里镜像源。 Index of /centos/7.9.2009/isos/x86_64/ | …...
适合国内用户的五款ChatGPT插件
众所周知使用ChatGPT3.5需要使用魔法且不稳定,订阅ChatGPT4.0每月需要支付20美元,并且使用次数有限制。对于那些不想每年花费240美元(超过1500元人民币)来使用GPT4.0的朋友们来说,还有别的办法吗? 答案是&…...
Dubbo Spring Boot Starter 开发微服务应用
环境要求 系统:Windows、Linux、MacOS JDK 8 及以上(推荐使用 JDK17) Git IntelliJ IDEA(可选) Docker (可选) 项目介绍 在本任务中,将分为 3 个子模块进行独立开发ÿ…...
linux中互斥锁,自旋锁,条件变量,信号量,与freeRTOS中的消息队列,信号量,互斥量,事件的区别
RTOS 对于目前主流的RTOS的任务,大部分都属于并发的线程。 因为MCU上的资源每个任务都是共享的,可以认为是单进程多线程模型。 【freertos】003-任务基础知识 在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式,但是如…...
安装docker服务,配置镜像加速器
文章目录 1.安装docker服务,配置镜像加速器2.下载系统镜像(Ubuntu、 centos)3.基于下载的镜像创建两个容器 (容器名一个为自己名字全拼,一个为首名字字母)4.容器的启动、 停止及重启操作5.怎么查看正在运行…...
CF 896 C Willem, Chtholly and Seniorious(珂朵莉树模板)
CF 896 C. Willem, Chtholly and Seniorious(珂朵莉树模板) Problem - C - Codeforces 大意:给出一个区间 , 要求进行四种操作 , 区间加 , 区间第k大 , 区间推平 , 区间求和。 珂朵莉树模板题 ÿ…...
Android Jetpack组件的全方位分析
Jetpack是一个用于简化Android应用程序开发的工具包,包含了一系列的组件和工具。Jetpack包含了很多组件,如LiveData、ViewModel、Room、Data Binding、Navigation等。 Jetpack组件是一种更高级别的抽象,它们可以提供更简洁、更易于使用的API。…...
Prometheus+Grafana+AlertManager监控SpringBoot项目并发送邮件告警通知
文章目录 PrometheusGrafanaAlertManager监控平台搭建新建SpringBoot项目为Prometheus提供指标新建项目,引入依赖新建接口,运行程序 推送指标到pushgateway 开始监控Grafana连接Prometheus数据源导入Grafana模板监控SpringBoot项目 邮件告警通知同系列文…...
猿辅导Motiff亮相IXDC 2023国际体验设计大会,发布新功能获行业高度关注
近日,“IXDC 2023国际体验设计大会”在北京国家会议中心拉开序幕,3000设计师、1000企业、200全球商业领袖,共襄为期5天的用户体验创新盛会。据了解,此次大会是以“设计领导力”为主题,分享全球设计、科技、商业的前沿趋…...
【QT】重写QAbstractLIstModel,使用ListView来显示多列数据
qt提供了几个视图来进行信息的列表显示,QListView可以用来显示继承QStractListModel的字符串列表中的字符串,默认的模型里面只包含一列的内容: 这里以qml为例子,先新建一个qml的项目,示例代码如下: 先创建一…...
【从零学习python 】64. Python正则表达式中re.compile方法的使用详解
文章目录 re.compile方法的使用进阶案例 re.compile方法的使用 在使用正则表达式时,我们可以直接调用re模块的match、search、findall等方法,并传入指定的正则表达式进行匹配。另外,我们还可以使用re.compile方法生成一个正则表达式对象&…...
北京网站域名备案/建设网站的基本流程
python爬虫scrapy基本使用超详细教程 http://www.guikeyun.com/cms/news/352587.html 一、介绍 官方文档:中文2.3版本 下面这张图大家应该很熟悉,很多有关scrapy框架的介绍中都会出现这张图,感兴趣的再去查询相关资料,当然学会…...
sea wordpress/手机端怎么刷排名
项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于web网页的疫情核酸检查预约系统,整个网站项目使用了B/S架构,基于java的springboot框架下开发;;通过后台设置医院信息、录入医院科室信息、录入医生信息、设…...
南翔企业网站开发建设/靠网络营销火起来的企业
最近在折腾大数据,需要搭建一个yum源。一般的做法是在CentOS中安装httpd,然后将rpm包放入/var/www/html下面,再执行[createrepo .]即可。 不过虚拟机对传文件终归是慢一拍,所以考虑到性能,想直接使用宿主机(…...
做网站没有学历的人会吗/优化关键词排名工具
阅读软件工程与计算机科学区别的文章,谈谈你的看法 从范围上来讲软件工程是一项工程,计算机科学是一个领域,所以计算机科学更广。 软件工程:诠释的是一项工程,主要内容是如何去规划和设计一个项目,让人们在…...
广东门户网站建设/seo与sem的关系
首先来看一张即时通讯里的一个用例图。 看这张图,第一反应是乱,没条理。再来分析下这张图,管理好友可以理解成一级用例,实际上它是一个虚拟用例,查找好友是个二级用例,以后的操作都是建立在查找好友的基础上…...
如何设置wordpress的语言/google推广方式和手段有哪些
有可能是作用域的问题...