七分钟“手撕”三大特性<多态>

目录

一、学习多态之前需要的知识储备

二、重写

1.什么是重写

2.重写可以干嘛

3.怎么书写重写

4.重载与重写的区别

三、向上转型

1.什么是向上转型?

2.向上转型的语法

3.向上转型的使用场景 

四、多态是什么

六、多态实现

七、多态的好处

八、多态的缺点 

九、向下转型


一、学习多态之前需要的知识储备

学习多态之前,我们得知道多态需要的知识储备,有了这个基础,我们才能更好的学习多态。

多态的发生需要三个条件(三个“要”):

(一)要继承

(二)要重写

(三)要向上转型

在之前的博客谈及过继承,可以翻阅我之前的博客,这里就不赘述了。因此,我们先需要学习重写与向上转型。请看:

二、重写

1.什么是重写

重写是指:书写方法时返回值和形参都不能改变。即外壳不变,核心重写!简单来讲:增加多点业务。

例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们不应该在原来老的类上进行修改(因为可能还有老用户在使用)正确做法是:新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我们当今的需求了。

2.重写可以干嘛

重写就是为了服务多态,为多态做继承可以认为是不同人做不同事,多写出一个一模一样的方法,打个不恰当的比方就是看人下菜

3.怎么书写重写

public class Animal {
    String name;
    int age;
//构造方法
    public Animal(String name,int age){
        this.name=name;
        this.age=age;
    }
    //这个eat方法与下面的eat方法一模一样(除了里面的内容),形成重写
    public void eat(){
        System.out.println(this.name+"吃饭");
    }
}

class Dog extends Animal{
    public Dog(String name,int age){
        super(name, age);
    }
    //eat方法重写,对于不同的对象(狗狗)用不同的方法
    public void eat(){
        System.out.println(this.name+"吃骨头");
    }
}

class Cat extends Animal{
    public Cat(String name,int age){
        super(name, age);
    }
    //eat方法重写,对于不同的对象(猫猫)用不同的方法
    public void eat(){
        System.out.println(this.name+"吃鱼");
    }
}

【方法重写的规则】

1.子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致。

2.被重写的方法返回值类型可以不同,但是必须是具有父子关系的。

3.访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为protected。

4.父类被static、private修饰的方法、构造方法都不能被重写。

5.重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写。

4.重载与重写的区别

三、向上转型

1.什么是向上转型?

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。 

2.向上转型的语法

语法格式:父类类型 对象名 = new 子类类型()

Animal animal = new Dog("puppy",2);

animal是父类类型,但可以引用一个子类对象,因为是从小范围向大范围的转换。 

3.向上转型的使用场景 

 【使用场景】

1. 直接赋值

2. 方法传参

3. 方法返回

public class Test {
    //方法传参的方法
    public static void eat(Animal animal){
        animal.eat();
    }
    //方法返回的方法
    public static Animal buyAnimal(String var){
        if("狗".equals(var) ){
            return new Dog("狗狗",1);
        }else if("猫" .equals(var)){
            return new Cat("猫猫", 1);
        }else{
            return null;
        }
    }

    public static void main(String[] args) {
        //直接赋值
        Animal animal=new Dog("puppy",2);
        //方法传参
        eat(new Dog("puppy",2));
        //方法返回
        Animal animal2 = buyAnimal("狗");
    }
}

向上转型的优点:让代码实现更简单灵活。

向上转型的缺陷:不能调用到子类特有的方法。

四、多态是什么

既然我们了解了重写以及向上转型,加上之前博客提到的继承,我们接下来来学习一下多态。

首先,多态是什么呢?

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 

六、多态实现

public class Animal {
    String name;
    int age;
    public Animal(String name,int age){
        this.name=name;
        this.age=age;
    }
    public void eat(){
        System.out.println(this.name+"吃饭");
    }
}

class Dog extends Animal{
    public Dog(String name,int age){
        super(name, age);
    }
    public void eat(){
        System.out.println(this.name+"吃骨头");
    }
}

class Cat extends Animal{
    public Cat(String name,int age){
        super(name, age);
    }
    public void eat(){
        System.out.println(this.name+"吃鱼");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal animal1=new Cat("花花",2);
        animal1.eat();
        Animal animal2=new Dog("puppy",2);
        animal2.eat();
        Animal animal3=new Animal("caddy",3);
        animal3.eat();
        
    }
}
//执行结果:
花花吃鱼
puppy吃骨头
caddy吃饭

对于不同的对象调用,产生的结果不一样。 

多态的本质就是动态绑定。动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

七、多态的好处

假设我们有以下代码:

class Shape {
//属性....
public void draw() {
    System.out.println("画图形!");
}
}
class Rect extends Shape{
@Override
public void draw() {
    System.out.println("♦");
}
}
class Cycle extends Shape{
@Override
public void draw() {
    System.out.println("●");
}
}

class Flower extends Shape{
@Override
public void draw() {
    System.out.println("❀");
}
}

1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else 

比如,假设我们不基于多态,我们会写出下列代码:

public static void drawShapes() {
    Rect rect = new Rect();
    Cycle cycle = new Cycle();
    Flower flower = new Flower();
    String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
for (String shape : shapes) {
if (shape.equals("cycle")) {
    cycle.draw();
} else if (shape.equals("rect")) {
    rect.draw();
} else if (shape.equals("flower")) {
    flower.draw();
}
}
}

 如果我们基于多态,会写出以下代码:

public static void drawShapes() {
// 我们创建了一个 Shape 对象的数组.
Shape[] shapes = {new Cycle(), 
new Rect(), new Cycle(),
new Rect(), new Flower()
};//我们通过把子类的对象放进父类的数组里面,也算向上转型
for (Shape shape : shapes) {
    shape.draw();
}
}

2. 可扩展能力更强 

如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低。

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

八、多态的缺点 

我们需要避免在构造方法中调用重写的方法:

一段有坑的代码.。我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法。并且在 B 的构造方法中调用 func。

class B {
public B() {
// do nothing
    func();
}
public void func() {
    System.out.println("B.func()");
}
}
class D extends B {
    private int num = 1;
@Override
public void func() {
    System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
    D d = new D();
}
}
// 执行结果
D.func() 0

构造 D 对象的同时, 会调用 B 的构造方法。

B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func。

此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0。

所以在构造函数内,尽量避免使用实例方法,除了final和private方法。 

九、向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。 

 

public class TestAnimal {
public static void main(String[] args) {
    Cat cat = new Cat("元宝",2);
    Dog dog = new Dog("小七", 1);
// 向上转型
    Animal animal = cat;
    animal.eat();
    animal = dog;
    animal.eat();
// 编译失败,编译时编译器将animal当成Animal对象处理
// 而Animal类中没有bark方法,因此编译失败
// animal.bark();
// 向上转型
// 程序可以通过编程,但运行时抛出异常---因为:animal实际指向的是狗
// 现在要强制还原为猫,无法正常还原,运行时抛出:ClassCastException
    cat = (Cat)animal;
    cat.mew();
// animal本来指向的就是狗,因此将animal还原为狗也是安全的
    dog = (Dog)animal;
    dog.bark();
}
}

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换。代码如下:

public class TestAnimal {
public static void main(String[] args) {
    Cat cat = new Cat("元宝",2);
    Dog dog = new Dog("小七", 1);
// 向上转型
    Animal animal = cat;
    animal.eat();
    animal = dog;
    animal.eat();
if(animal instanceof Cat){
    cat = (Cat)animal;
    cat.mew();
}
if(animal instanceof Dog){
    dog = (Dog)animal;
    dog.bark();
}
}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员过了35岁没人要?“这行越老越香”

程序员35岁失业?参加完OceanBase开发者大会,我又悟了! 周六参加了OceanBase2024 开发者大会的现场,来之前我其实挺忐忑的,我觉得一个数据库产品的发布会,能有什么新鲜的东西? 踏入酒店的那一刻&…

经风靡全球的 PHP 为何逐渐失去优势?

TIOBE 编程语言人气指数发布更新,并提出“PHP 的魔力是否正在消散?”的灵魂拷问。今年 4 月,PHP 在 TIOBE 编程语言指数榜上仅位列第 17,“成为其有史以来的最低排位”。 暴露 PHP 人气急剧下滑的还不只是 TIOBE 榜单。在年度 Sta…

MP4转gif如何操作?一个常见方法分享

MP4是一种视频格式,而gif则是图片格式。当我们需要将MP4格式的时候转成gif格式图片的时候要怎么操作呢?怎样在不下载软件的情况下在线转换格式呢?很简单,通过使用gif图片制作(https://www.gif.cn/)工具-GIF…

Android开发者必备:RootEncoder引领实时流媒体传输革新

Android开发者必备:RootEncoder引领实时流媒体传输革新 I. 引言 A. RootEncoder简介 RootEncoder for Android(rtmp-rtsp-stream-client-java)是一个功能强大的流编码器,旨在通过多种协议(包括RTMP、RTSP、SRT和UDP…

VR全景创业项目应该如何开展?未来有市场吗?

伴随着5G网络的发展,VR全景得到了众多的关注和提升。与此同时,各行各业都开始关注自身产业在互联网的展示效果,因为年轻一代的生活已经离不开互联网,而VR全景在互联网上的3D展示效果能给商家带来流量,提升营业额。 随着…

ERROR: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).

今天本来想在A服务器上传文件给B服务器的结果发现明明给root用户设置了密码就是远程登陆不了,后来才发现在容器中很多服务都是没有的,所以刚安装后忘记了修改配置文件,导致远程登陆失败。 报错: 解决方法: 在/etc/ssh…

【电控实物-infantry】

云台电机参数 电机内部参数 相电阻:Rs1.8欧 相电感:Ls5.7810^-3H 转矩常数:Kt 0.741 NM/A 转动惯量:J KG-m^2 电机接收数据:-16384到16384(-3A到3A) 电机反馈:速度RPM rad/s (2πrpm)/60 C板陀螺仪&…

苍穹外卖学习笔记(9.订单状态定时处理,来电提醒,客户催单)

目录 一、订单状态定时处理1、需求分析设计2、代码开发3、测试 二、来单提醒1、需求分析设计2、代码开发3、测试 三、客户催单1、需求分析设计2、代码开发3、测试 四、相关知识1、Spring Task2、WebSocket 一、订单状态定时处理 1、需求分析设计 2、代码开发 创建orderTask类…

初学若依笔记

初学若依 下载ruoyi(以前后端分离板为例) https://ruoyi.vip/ 部署 安装mysql安装redis将数据库和redis配置到若依 配置文件为 ruoyi-admin\src\main\resource\application-druid.yml 运行 略 开发自己的功能 创建模块 为了不影响原有功能,创建一个模块写自…

物联网(iot)深度解析——FMEA软件

物联网即IoT,是指通过各种信息传感器、射频识别技术、全球定位系统、红外感应器、激光扫描器等各种装置与技术,实时采集任何需要监控、连接、互动的物体或过程,采集其声、光、热、电、力学、化学、生物、位置等各种需要的信息,通过…

顺序栈算法库构建

学习贺利坚老师,顺序栈,构建顺序栈算法库 数据结构之自建算法库——顺序栈_设计一个主函数实现对顺序栈进行操作测试,测试方法,依次把元素-CSDN博客文章浏览阅读4.9k次,点赞10次,收藏10次。本文针对数据结构基础系列网络课程(2)&…

CRAFT文字检测算法解析和基于C++和TensorRT的推理实现

本文讲解了CVPR 2019的一篇文字检测算法《Character Region Awareness for Text Detection》的原理,并给出我使用C和TensorRT重新实现的推理,速度比原版代码快12倍。 论文:https://arxiv.org/pdf/1904.01941.pdf 官方代码:https:…

自然语言处理 (NLP) 的技术演变史

一、简述 本文的目标是了解自然语言处理 (NLP) 的历史,包括 Transformer 体系结构如何彻底改变该领域并帮助我们创建大型语言模型 (LLM)。 基础模型(如 GPT-4)是最先进的自然语言处理模型,旨在理解、生成人类语言并与之交互。 要理…

IPEmotion轻松解决急停设备的控制与数据存储问题

一 背景 众所周知,急停操作在各种工业领域中都扮演着非常重要的角色。在一个个紧急情况下,及时采取急停操作可节省宝贵时间,避免人身伤害或设备损坏,降低安全风险,尤其是在新能源测试中,出于对高压电性能方…

linux 关闭不了docker服务

[rootiZ2ze7y4akbxb1yjoydztxZ ~]# systemctl stop docker Warning: Stopping docker.service, but it can still be activated by: docker.socket 在 systemd 系统中,服务和套接字是分开管理的。docker.socket 是一个套接字单元,用于监听 Docker 的 API…

小程序AI智能名片S2B2C商城系统:五大营销技术模块深度剖析

在当今数字化营销的时代,小程序AI智能名片S2B2C商城系统凭借五大核心营销技术模块,为企业提供了强大的私域流量管理与营销能力。下面我们将逐一剖析这五大模块,看它们如何共同助力企业实现精准营销与业务增长。 一、小程序:用户触…

力扣刷题 70.爬楼梯

题干 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&…

机器学习和深度学习 -- 李宏毅(笔记与个人理解)Day 23

Day 23 Self - Atention 变形 关于很多个former 的故事 痛点: 在于做出注意力矩阵之后的运算惊人 由于self - attention 一般都是在big model 的一部分,所以,一般不会对模型造成决定性的影响, 只有当model 的输入较长的时候&am…

求臻医学MRD产品斩获2023年度肿瘤标志物年度十大创新技术产品奖

2024年4月20日,中国肿瘤标志物学术大会开幕式暨名家讲坛在南京隆重召开! 会议期间,中国抗癌协会肿瘤标志专业委员会联合中国抗癌协会肿瘤临床检验与伴随诊断专业委员会、中国抗癌协会肿瘤基因诊断专业委员等共同发布“2023 年度肿瘤标志物创新技术产品”…

Java 提取HTML文件中的文本内容

从 HTML 文件中提取文本内容是数据抓取中的一个常见任务,你可以将提取的文本信息用于编制报告、进行数据分析或其他处理。本文分享如何使用免费 Java API 从HTML 文件中提取文本内容。 安装免费Java库: 要通过Java提取HTML文本,需要用到Free…