【Java SE】多态

🥰🥰🥰来都来了,不妨点个关注叭!
👉博客主页:欢迎各位大佬!👈

在这里插入图片描述

文章目录

  • 1. 多态
    • 1.1 多态是什么
    • 1.2 多态的意义
    • 1.3 多态的实现条件
  • 2. 重写
    • 2.1 重写的概念
    • 2.2 重写的规则
    • 2.3 重写与重载的区别
    • 2.4 重写的设计
  • 3. 向上转型和向下转型
    • 3.1 向上转型
    • 3.2 向下转型
    • 3.3 instanceof关键字
  • 4. 多态的优缺点
    • 4.1 多态的优点
    • 4.2 多态的缺点

1. 多态

面向对象三大特性:封装、继承、多态
今天我们一起来看看多态这一特性~~~

1.1 多态是什么

在生活中,如果遇到特别伤心的事情或者心情很沮丧,可能就会哭泣,但在不同人身上,哭泣的形式不一样,比如"臣妾做不到",小女孩哇哇大哭,还有大耳朵图图抱着妈妈的腿哭泣等等。总之,同一件事情,发生在不同对象上,表现的形式是不一样的~
在这里插入图片描述多态】通俗来说,多种形态,即去完成某个行为,当不同的对象去完成时会产生出不同的状态

1.2 多态的意义

多态的意义
在于提高代码的复用性扩展性,同时实现接口统一,并十分灵活,可以根据不同的输入参数或条件,调用不同的子类方法实现不同的功能,易于维护和修改(本期内容结尾将重点提到)

1.3 多态的实现条件

在Java中实现多态的条件如下(缺一不可):
(1) 必须在继承
(2) 子类必须要对父类中方法进行重写
(3) 通过父类的引用调用重写的方法(向上转型)
多态体现的方面:当传递不同类对象时,会调用对应类中的方法
代码

public class Animal {String name;String gender;int age;public Animal(String name,String gender, int age) {this.name = name;this.gender = gender;this.age = age;}public void eat() {System.out.println(name+"吃饭");}
}
public class Cat extends Animal{public Cat(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"吃🐟");}
}
public class Dog extends Animal{public Dog(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"吃骨头");}
}
public class Bird extends Animal{public Bird(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"啄米");}
}
public class Test {public static void eat(Animal a) {a.eat();}public static void main(String[] args) {Cat cat = new Cat("柚子","雌",2);Dog dog = new Dog("球球","雄",1);Bird bird = new Bird("泡芙","雌",2);eat(cat);eat(dog);eat(bird);}
}

运行结果
在这里插入图片描述
解释说明
在上述代码中,Animal、Cat、Dog和Bird类是类的实现者写的,Test类是类的调用者写的
当类的调用者在编写 eat 这个方法的时,传进来的参数类型为 Animal父类,在该方法内部并不知道当前的a 引用指向的是哪个类型,哪个子类的实例,即a这个引用调用 eat方法可能会有多种不同的表现(a引用的实例相关,比如猫类实例调用、狗类实例调用等,eat表现的形式不同),这种行为称为多态
图示
在这里插入图片描述
@Override
@Override是jdk的注解,用于指示一个方法是重写了父类中的方法
这个注解只在编译时有效,不会保留在生成的字节码文件中
使用 @Override 注解的优点:
1)提高代码的可读性安全性
2)在编译时检查可能的错误
但它不是必需要写的,只要正确地重写了父类中的方法,不使用 @Override 注解,代码仍能够正常运行
(即使用或不使用取决于编码风格和习惯)

2. 重写

2.1 重写的概念

重写】也称为覆盖,重写是子类对父类实现过程进行重新编写, 返回值形参都不能改变,即外壳不变,核心重写,重写的好处是子类可以根据需要,定义特定于自己的行为,即子类能够根据需要实现父类的方法

2.2 重写的规则

重写规则
1)子类在重写父类的方法时,一般必须与父类的返回值类型方法名 (参数列表) 完全一致
2)被重写的方法返回值类型可以不同,但必须具有父子类关系
3)访问权限不能比父类中被重写的方法的访问权限更低(如父类方法被public修饰,则子类中重写该方法不能声明为 private)
4)父类被staticprivatefinal修饰的方法、构造方法都不能被重写
5)重写的方法可使用 @Override 注解来显式指定,能进行一些合法性校验,检查可能会出现的错误(如不小心将方法名字写错, 此时编译器就会发现父类中没有该方法,则编译报错,提示无法构成重写)

2.3 重写与重载的区别

在这里插入图片描述
在这里插入图片描述

2.4 重写的设计

重写的设计原则】对于已经投入使用的类,尽量不要进行修改,最好是重新定义一个新的类,重复利用其中共性的内容,并添加或者改动新的内容
举一个栗子吧~
例如之前的电视机,只能看正在播放的频道,而当今时代,科技越来越发达,技术在进步,现在的电视不仅可以看正在播放的频道,还可以回看,直播等等,而我们不应该直接在原来的类修改,因为原来的类可能仍有用户正在使用,而正确的解决方式为,新建一个新型电视机的类,对可以看的内容这个方法进行重写,增添更多的功能,即达到需求
在这里插入图片描述
静态绑定】即在编译时,根据用户所传递实参类型就确定具体调用哪个方法,代表:函数重载
动态绑定】即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用哪个类的方法(发生多态的基础)

3. 向上转型和向下转型

3.1 向上转型

向上转型】实际上是创建一个子类对象,当父类对象使用
语法格式】父类类型 对象名 = new 子类类型();
语法举例

Animal animal = new Bird(“泡芙”,“雌”,2);

animal是父类Animal类型,即小的范围变成大的范围(是可以的),比如猫、狗和鸟等都是动物,将子类对象转化为父类引用是合理、安全的,大的范围包含小的范围

使用场景
1)直接赋值 2)方法传参 3)方法返回 【具体使用代码举例如下】:

public class Test1 {public static void main(String[] args) {Cat cat = new Cat("柚子","雌",2);Dog dog = new Dog("球球","雄",1);//1.直接复制 子类对象赋值给父类对象Animal bird = new Bird("泡芙","雌",2);eat(cat);eat(dog);eat(bird);}//2.方法传参 形参的类型为Animal父类,可接受任意子类对象,即animal1的类型可以是猫、狗、鸟等子类public static void eat(Animal animal1) {animal1.eat();}//3.方法返回 返回任意子类对象public static Animal guessAnimal(String name) {if("球球".equals(name)) {return new Dog("球球","雄",1);}return null;}
}

优点
让代码实现更简单灵活
缺点
不能调用到子类特有的方法只能调用父类的方法

3.2 向下转型

向下转型】子类对象向上转型后当父类对象方法使用,再无法调用子类的方法,如需调用子类特有的方法,将父类引用再还原为子类对象即可,即向下转型,在Java中,向下转型是从一个更通用的类型向一个更具体的类型转换的过程
在这里插入图片描述
语法格式】子类对象名 = (子类类型) 对象名
语法举例

bird = (Bird)animal;

使用场景
将它们转回具体的类型以利用它们的具体实现的情况

public class Animal {String name;String gender;int age;public Animal(String name,String gender, int age) {this.name = name;this.gender = gender;this.age = age;}public void eat() {System.out.println(name+"吃饭");}
}
public class Cat extends Animal{public Cat(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"吃🐟");}public void meow() {System.out.println("猫在叫~");}
}
public class Dog extends Animal{public Dog(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"吃骨头");}public void bark() {System.out.println("狗在叫~");}
}
public class Bird extends Animal{public Bird(String name,String gender,int age) {super(name, gender, age);}@Overridepublic void eat() {System.out.println(name+"啄米");}public void chirp() {System.out.println("小鸟叫~");}}
public class Test2 {public static void main(String[] args) {Cat cat = new Cat("柚子","雌",2);Dog dog = new Dog("球球","雄",1);Bird bird = new Bird("泡芙","雌",2);//向上转型Animal animal = cat;animal.eat();animal = dog;animal.eat();animal = bird;animal.eat();//向下转型//程序可以通过编程但是会抛出异常,animal实际指向的是鸟,但现在强制还原为猫,无法还原//cat = (Cat)animal;//cat.meow();//animal指向的是鸟,将animal还原为鸟是安全的bird = (Bird)animal;bird.chirp();//instanceof 判断它左边的对象是否是它右边的类的实例,返回boolean的数据类型,是返回true否则返回false;if(animal instanceof Cat) {cat = (Cat)animal;cat.meow();}if(animal instanceof Dog) {dog = (Dog)animal;dog.bark();}//animal指向的是鸟,左边的对象animal是右边鸟类的实例,为true,执行if内容语句if(animal instanceof Bird) {bird = (Bird) animal;bird.chirp();}}
}

运行结果
在这里插入图片描述
解释说明
在这里插入图片描述

优点
可访问更具体类型的特定方法和属性,明确正在处理的具体类型
缺点
不安全,万一转换失败,运行时会抛异常,Java中为了提高向下转型的安全性,引入instanceof关键字 ,如该表达式为true,则可以安全转换,较为麻烦

3.3 instanceof关键字

概念】instanceof是Java中的保留关键字
作用】测试它的左边对象是否是它的右边类的实例,返回类型:boolean类型
用法】res = 对象名 instanceof 类名;
举例】以上述代码举例
在这里插入图片描述

4. 多态的优缺点

4.1 多态的优点

1)能够避免使用大量的 if - else
如果需要打印多个形状,不基于多态写,则会有好几个if语句

public class Shape {public void draw() {System.out.println("画图形~");}
}
public class Rectangle extends Shape{@Overridepublic void draw() {System.out.println("◇");}
}
public class Cycle extends Shape{@Overridepublic void draw() {System.out.println("○");}
}
public class Fish extends Shape{@Overridepublic void draw() {System.out.println("🐟");}
}
public class Test3 {public static void drawShapes() {Rectangle rectangle = new Rectangle();Cycle cycle = new Cycle();Fish fish = new Fish();String[] shapes = {"cycle","rectangle","fish"};for(String x : shapes) {if(x.equals("cycle")) {cycle.draw();}else if(x.equals("rectangle")) {rectangle.draw();}else if(x.equals("fish")) {fish.draw();}}}public static void main(String[] args) {drawShapes();}
}

基于多态编写代码,创建一个Shape对象的数组,则简洁明了~

public class Test3 {public static void drawShapes1() {Shape[] shapes = {new Cycle(),new Rectangle(),new Fish()};for(Shape x: shapes) {x.draw();}}public static void main(String[] args) {drawShapes1();}
}

两者打印结果一致,所以可以避免大量的if-else语句
在这里插入图片描述
2)可扩展能力更强
如果要新增加一种新的形状,使用多态方式编写的代码改动成本较低,体现可扩展性强,比如我们要增加三角形这个形状类型

public class Triangle extends Shape{@Overridepublic void draw() {System.out.println("△");}
}

解释说明】基于多态代码,对类的使用者来说,drawShapes方法只需创建一个新类的实例,改动成本较低,对于不基于多态的代码, 则需把drawShapes方法中的 if - else 进行修改,改动成本更高

4.2 多态的缺点

代码的运行效率降低
1)属性没有多态性,当父类和子类都有同名属性时,通过父类引用只能引用父类自己的成员属性
2)构造方法没有多态性
A为父类,在A类构造方法中调用func()方法,B为子类,B类中重写func()方法
代码举例

public class A {public A() {func();}public void func() {System.out.println("A.func()");}
}
public class B extends A{private String str = "~";@Overridepublic void func() {System.out.println("B.func()"+" "+str);}
}
public class Test4 {public static void main(String[] args) {B b = new B();}
}

运行结果
在这里插入图片描述
解释说明
构造B对象的同时,会调用A的构造方法
A的构造方法中调用func()方法,此时会触发动态绑定,即在编译时不能确定方法的行为,等程序运行时,确定是具体调用B类中的 func()方法,此时B对象自身还没有构造, str是未初始化的状态,为null,如果具备多态性,str的值应该是~,即构造方法没有多态性
结论】在构造函数内,尽量避免使用实例方法,除final和private方法
即尽量不要在构造器中调用方法,如果这个方法被子类重写,就会触发动态绑定,但此时子类对象还没构造完成,可能会出现一些隐藏但很难发现的问题,带来不必要的麻烦
💛💛💛本期内容回顾💛💛💛
在这里插入图片描述✨✨✨本期内容到此结束啦~下期再见!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MP4 封装格式详解

MP4 封装格式详解 MP4 封装格式详解简介概念与术语MP4 整体结构Box 结构Box HeaderBox Data MP4 典型 Boxftyp(File Type Box)moov(Movie Box)mvhd(moov header)traktkhd(track header box&…

vue3大事件项目3

弹框验证 先准备变量: const formModel ref({ cate_name: , cate_alias: }) 还有规则: const rules { cate_name: [ { required: true, message: please input name, trigger: blur }, { pattern: /^\S{1,10}$/, message: must be 1-10, trigger: blur } ], …

太阳光光照试验耐久性老化试验使用太阳光模拟器系统

上海科迎法电气科技有限公司生产的太阳光模拟器系统主要应用于太阳能研究、材料研究、光伏组件测试、空间环境模拟器、植物生长研究、光热模拟等领域,主要表现特征为: 1. 太阳能研究:可用于模拟不同光照条件下太阳能电池的性能测试和研究&am…

高清视频素材,免费下载,收藏好这6个网站。

国内大部分视频素材网站都需要付费购买,这让很多从事视频剪辑的朋友不知道去哪里找免费的视频素材,本期就给大家分享我收藏多年的6个视频素材网站,都可以免费下载,还可以商用,而且国内外的都有哦,有需要的朋…

java-spring 图灵 02 手写spring

01.idea中创建一个maven管理的空项目 02.模拟创建出spring容器类,这里叫wzpApplicationContext,创建的时候会自动加载配置类的数据 public class wzpApplicationContext {private Class configClass;public wzpApplicationContext(Class configClass) …

【Qt 学习笔记】QWidget的windowOpacity属性 | cursor属性 | font属性

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ QWidget的windowOpacity属性 | cursor属性 | font属性 文章编号&#…

解决 MSYS2 Qt 6.7 默认 stylesheet 在 windows 11 下的显示故障

项目场景: MSYS2 升级到 Qt6.7.0,发现显示故障,所有Qt6程序以及 QtCreator的SpinBox都显示不全,Combox的底色不对。 问题描述 2024年4月1日,pacman升级MSYS2后,Qt6遇到风格错误。 msys环境: …

ThingsBoard实现告警规则创建并生成报警信息

一、概述 1.概念 2.告警规则 3.简单报警条件 步骤1. 打开设置配置 ​步骤2. 单击警报规则 ​步骤3. 单击警报条件 ​步骤4. 单击过滤条件 ​步骤5. 选择数据键 ​步骤6. 设置条件 ​步骤7. 保存条件 ​步骤8. 应用更改 4.测试告警 1、使用MQTT发送遥测属性 2、查看…

数据结构:双向链表

一.双向链表的结构 最常用的链表就是单链表和双向链表。我们首先要知道,链表有八种分类。单链表是不带头单向不循环链表。而此篇博客要讲的是带头双向循环链表。 结构如下: 注意:带头链表里的头节点,实际为“哨兵位”&#xff0…

【python】python饮料销售数据分析可视化(源码+数据集)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

机器人瓶胚检测工作站(H3U脉冲轴控制)

1、变量定义 2、程序监控1 2、 程序监控2 3、程序监控3 机器人输送料和机构的动作安全尤为重要,下面我们讨论下安全联锁控制逻辑 4、相机拍照触发信号 5、相机拍照触发时序

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 基本介绍

【SpringBoot】获取参数

获取参数 传递单个参数传递多个参数传递对象后端参数重命名传递数组传递 json 数据获取 URL 中参数上传文件获取 cookie 和 session获取cookie获取session 传递单个参数 RequestMapping("/user") RestController public class UserController {// 传递单个参数Reque…

简单好用的SaaS知识库工具都在这了,看完赶紧收藏!

在信息飞速发展的今天,企业如何有效地管理海量的信息和知识成为了提高工作效率的关键。SaaS知识库工具正成为企业寻求的解决方案,它们不仅能够帮助团队组织文档,而且优化知识分享流程。现在就让我们来看看市场上几款简单又好用的SaaS知识库工…

华为云配置安全组策略开放端口

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C 🔥座右铭:“不要等到什么都没有了,才下…

C语言 | 内存函数memcpy,memmove,memset,memcmp

目录&#xff1a; 1. memcpy使用和模拟实现 2. memmove使用和模拟实现 3. memset函数的使用 4. memcmp函数的使用 头文件&#xff1a;<string.h> 1. memcpy使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); • 从source的…

【CPA考试】2024注册会计师报名照片尺寸要求解读及手机拍照方法

随着2024年注册会计师考试的临近&#xff0c;众多会计专业人士和学生都开始准备报名参加这一行业的重要考试&#xff0c;报名时间为4月8日至4月30日。报名过程中&#xff0c;一张符合要求的证件照是必不可少的。本文将为您详细解读2024年注册会计师考试报名照片的尺寸要求&…

Git以及Gitlab的快速使用文档

优质博文&#xff1a;IT-BLOG-CN 安装git 【1】Windows为例&#xff0c;去百度下载安装包。或者去官网下载。安装过秳返里略过&#xff0c;一直下一步即可。丌要忉记设置环境发量。 【2】打开cmd&#xff0c;输入git –version正确输出版本后则git安装成功。 配置ssh Git和s…

C++ 之 【类与对象】 从入门到精通一条龙服务 进阶篇(类的6个默认成员函数,构造,析构。。。)

以后把闹钟换成唢呐&#xff0c;醒了就起床&#xff0c;不醒就上天堂 一、类的6个默认成员函数 二、构造函数 1.概念 2.特性 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 3.前置和后置重载 六…

rancher踩坑日志:prometheus访问kubelet 10250端口提示鉴权失败

该原因是因为kubectl禁止了非授权用户访问10250端口来获取node的数据。 解决思路&#xff1a; 添加prometheus访问kubelet时带上证书进行验证匹配 --> 由于我的prometheus是rancher安装的&#xff0c;不知道要怎么修改所以研究了一会没研究明白就放弃了。设置prometheus访问…