【Java基础篇 | 面向对象】—— 聊聊什么是多态(下篇)

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【JavaSE_primary】
本专栏旨在分享学习JavaSE的一点学习心得,欢迎大家在评论区讨论💌
在这里插入图片描述

目录

  • 一、动态绑定和静态绑定
    • 动态绑定
    • 静态绑定
  • 二、向上转型和向下转型
    • 向上转型
    • 向下转型
  • 三、多态的优缺点
  • 四、避免在构造方法中去调用重写的方法

一、动态绑定和静态绑定

动态绑定

动态绑定(也叫晚绑定或者运行时绑定):在编译时不能确定方法的行为,需要等到程序运行时才能够确定调用的具体是哪个类中的方法。

什么时候会用到动态绑定:
当一个子类继承自一个父类并重写了父类的方法时,就会涉及到Java的动态绑定。在运行时,实际上调用的是子类重写后的方法,而不是父类的方法。
举个栗子:在这里插入图片描述
解释:子类Dog重写了父类Animal中的eat方法,在main方法中创建了一个Animal类型的引用animal,并将其实例化为Dog对象。最后通过调用它的eat方法,会根据实际对象的类型,动态地绑定到对应的方法上。
代码编译时的确调用的是父类Animal中的eat方法,但是最终运行结果是调用了子类中的eat方法(本质就是因为这里发生了重写,同时这里是通过父类来去调用子类中重写的这个eat方法的)。

动态绑定发生之前必须具备两个条件:

  • 第一:父类和子类中必须存在重写的方法。
  • 第二:通过父类的引用来去调用重写的方法。

静态绑定

静态绑定(也称为早绑定):在编译时,根据用户所传递参数个数、实参类型等就可以确定具体调用哪个方法。

比如我们之前学过的重载就是很好的一个静态绑定的例子。
举个栗子:

public add(int a,int b,int c) {
	return a + b + c;
}

public void eat(int a,int b) {
    return a + b;
}

二、向上转型和向下转型

向上转型

向上转型:简单来说就是用父类引用来接受子类对象

向上转型发生的三种时机:直接赋值传参返回值

第一种时机:
直接赋值的方式:Animal animal = new Dog("cc",10);

第二种时机:传参。
在这里插入图片描述

第三种时机:返回值。
在这里插入图片描述

再来回顾多条的概念:父类引用引用子类对象时,当引用的子类对象的对象类型不一样时,通过父类引用去调用父类和子类重写的方法,此时同一个引用可以呈现出不同的状态,我们把这个思想称之为多态。官方一点:多态是指对象根据其实际的类型来执行不同的操作或表现出不同的行为的能力。

向上转型优点:让代码实现更加灵活。
向上转型缺点:不能调用子类特有的方法而只能调用父类和子类重写的方法。

向下转型

重要的事情放前面:向下转型不是很安全,一般很少用到。

向下转型概念:将一个子类对象经过向上转型之后当成父类方法使用,此时就无法调用子类的特有方法(而只能调用父类和子类重写的方法);但是有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

向下转型是非常不安全的,转换失败的话运行时就会抛出异常。所以Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
举个栗子:
在这里插入图片描述
下面这种方式才是安全的使用方法:
在这里插入图片描述

三、多态的优缺点

多态优点:能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
多态缺点:可扩展能力更强

降低代码的 “圈复杂度”,举栗请看如下代码:

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 Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("三角形");
    }
}

现在我们如果想打印不同的图形,如果基于多态来实现的话,代码如下:

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

如果我们基于多态来进行实现的话,代码只有那么几行,请看:

public static void drawShapes2() {
    // 这里创建了一个 Shape 对象的数组.
        Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),
                new Rect(), new Triangle()};
        for (Shape shape : shapes) {
            shape.draw();
        }
    }

至于多态的拓展能力强这里优点,我们还是拿上面的代码进行举栗:除了上述图形之外,我们还可以添加其它各种各样的图形。

多态缺陷:
1.属性是没有多态性的:方法我们可以进行重写,但是属性是不可进行重写的(当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性)。
2.我们应该避免在构造方法中去调用重写的方法(具体为啥请看下面一小节)。

四、避免在构造方法中去调用重写的方法

我们还是拿代码进行举例,请看:

class B {
    public B() {
        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 对象的同时, 会调用 B 的构造方法。
  • B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func。(由于此时 D 对象自身还没有构造, 所以num 处在未初始化的状态。
  • 所以在构造函数内,尽量避免使用实例方法,除了final和private方法。

在构造方法中调用重写方法可能会导致意想不到的结果。因为在对象初始化时,子类重写的方法可能还没有被执行,所以调用该方法可能会得到父类中的默认实现,而不是子类所期望的行为。

好了,以上就是本文的全部内容啦,就到这里吧。再见啦友友们!!!

在这里插入图片描述

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

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

相关文章

C++ string类(2)—成员访问、插入、删除、替换、查找和交换操作

目录 一、成员访问 1、[ ]&at 2、front( )&back( ) 二、插入元素 三、删除元素 四、替换元素 五、查找元素 1、查找第一次出现位置 2 、在指定范围内查找 六、交换字符串 七、c_str 八、rfind&substr 一、成员访问 1、[ ]&at 虽然二者功能一样&…

【微信小程序】上传头像 微信小程序内接小程序客服

这里写目录标题 微信小程序上传头像使用button按钮包裹img 微信小程序内接小程序客服使用button按钮跳转客服 微信小程序上传头像 使用button按钮包裹img 原本思路是只使用image标签再加上chooseImg,但发现使用button标签上传头像这种方法更实用。微信小程序文档上…

栈实现队列,力扣

题目地址: 232. 用栈实现队列 - 力扣(LeetCode) 难度:简单 今天刷栈实现队列,大家有兴趣可以点上看看题目要求,试着做一下。 题目: 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支…

简单句子成分、阅读技巧

四、段落的主旨题:问这一段讲了什么(一般都在段落的第一句话或最后一句话) 词汇题的答案一般都在生词的上一句或者下一句 做题步骤: 1、先标段落 2、看题,划出关键词 3、去原文定位,标注中文意思 4、第一遍…

类和对象——(5)定义对象数组

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言​📝 芳华没有草稿纸,我们永久不…

异常(C++)

异常 前言一、程序的错误分类二、异常1. 概念2. 捕获异常的关键字和格式3. 异常的使用异常的原则异常再抛出异常说明注意事项 4. 自定义异常体系5. C标准库的异常体系 三、总结 前言 在程序运行时经常碰到一些错误,例如年龄、身高不能为负,除数为0等&…

阿里微服务质量保障系列:性能监控最佳实践

建设一体化性能监控平台 随着互联网技术的不断发展,企业的业务规模和复杂度也在不断增加。为了保证业务的稳定性和可靠性,企业需要对其系统进行全面的性能监控。而一体化性能监控就是一种集成了多种监控工具和技术的综合性监控方案,可以帮助…

PPT设置背景颜色

问题描述:PPT如何设置背景颜色? 问题解决:设计→设置背景格式→颜色→蓝色(最好选择看着比较舒服的颜色)

软件设计模式原则(三)单一职责原则

单一职责原则(SRP)又称单一功能原则。它规定一个类应该只有一个发生变化的原因。所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原…

linux下安装nginx

第一步:压缩包 准备压缩包,最好准备一个稳定的版本:下载地址 我这边选用的是1.24.0双版本号 第二步:解压 在相对应的目录下,执行命令:tar -zxvf nginx-1.18.0.tar.gz 第三步:配置\编译 推荐…

【vue】尚硅谷vue3学习笔记

Vue3快速上手 1.Vue3简介 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址:https://github.com/vuejs/vue-next/release…

图论|并查集理论基础 1971. 寻找图中是否存在路径

什么是并查集 并查集是一种数据结构,用于处理一些不交集的合并及查询问题。它支持两种操作: 查找(Find):确定某个元素属于哪个子集。它可以用来判断两个元素是否属于同一个子集。 合并(Union)&…

Button初了解

Button 由TextView派生而来,二者的区别有: Button有默认的按钮背景,TextView默认无背景Button的内部文本默认居中对齐,而TextView的默认靠左对齐2023年以前,Button默认将英文换为大写,而TextView保持原始的…

springboot助农管理系统

springboot助农管理系统 成品项目已经更新!同学们可以打开链接查看!需要定做的及时联系我!专业团队定做!全程包售后! 2000套项目视频链接:https://pan.baidu.com/s/1N4L3zMQ9nNm8nvEVfIR2pg?pwdekjv 提…

虚拟化逻辑架构: VM VirtualBox 指定6.0.24版本开启硬件辅助虚拟化功能

目录 一、实验 1.安装VM VirtualBox-6.0.24 2.安装VM VirtualBox-6.1.26 3.再次重新安装VM VirtualBox-6.0.24 二、问题 1.系统开机报错 2.Ubuntu系统无法自适应VM VirtualBox系统边框 3.VirtualBox如何开启无缝模式 3.Ubuntu如何查询软件是否已经安装 一、实验 1.安…

Redis之五大基础数据类型(详细总结 面试必备)

Redis之五大基础数据类型 Redis 共有 5 种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。 这 5 种数据类…

二叉树在线OJ

二叉树的构建及遍历 本题目的要求是: 输入一个数组,里面存放了若干个字符,#代表了空指针,数组中的顺序是 是先序遍历,然后要求你用中序输出 首先我们要做的就是构造结构体: typedef struct TreeNode {char…

leetcode:232. 用栈实现队列

一、题目 原题链接:232. 用栈实现队列 - 力扣(LeetCode) 函数原型: typedef struct //我的队列结构定义 { } MyQueue; MyQueue* myQueueCreate() //我的队列创建及其初始化 void myQueuePush(MyQueue* obj, int x) //我的队…

shell编程awk命令详解(超详细)

文章目录 前言一、awk命令介绍1. awk命令简介2. awk命令的基本语法3. 常用的awk命令选项4. 常用的awk内置变量 二、awk命令示例用法1. 打印整行2. 打印特定字段3. 根据条件筛选行4. 自定义分隔符5. 从文件中读取awk脚本 总结 前言 awk命令是一种强大的文本处理工具&#xff0c…

【理解ARM架构】中断处理 | CPU模式

🐱作者:一只大喵咪1201 🐱专栏:《理解ARM架构》 🔥格言:你只管努力,剩下的交给时间! 目录 🍜中断🍨GPIO中断代码实现 🍜CPU🍨CONTROL…