Java之多态

文章目录

  • 1. 多态
    • 1.1 多态的概念
  • 2. 方法的重写
  • 3. 向上转型
    • 3.1
    • 3.2 发生向上转型的时机
  • 4. 动态绑定和静态绑定
  • 5. 什么是多态
    • 5.1
    • 5.2 多态的优缺点
  • 6. 避免在构造方法中调用重写的方法
  • 7. 向下转型![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fd1fa83140d94f37ab3b881b0df41305.png)

1. 多态

1.1 多态的概念

去完成某个行为,不同的对象去完成会产生不同的状态。例如,猫和狗都在叫,而猫的叫的是喵喵,狗叫的是汪汪。

在讲解多态之前我们先学习什么是向上转型向下转型方法重写

2. 方法的重写

重写(override),也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写。

构成方法重写的条件

  1. 方法名相同
  2. 方法的参数列表相同(个数、顺序、类型)
  3. 方法的返回值相同

例如:
在这里插入图片描述
上述两个 bark 方法,实现了方法的重写。重写的方法通常会有 @Override 来修饰,表示方法的重写,可以用来提示重写的方法是否出现错误,如果出现错误@Override处会报错。
在这里插入图片描述
注意

  1. 静态方法不能被重写
  2. 被private修饰的方法不能被重写
  3. 被final修饰的方法不能被重写
  4. 如果方法被重写,子类的访问权限要大于等于父类的访问权限
    private < 包访问权限 < protected < public

跟重载是有区别的,注意区分哦
在这里插入图片描述

3. 向上转型

3.1

在这里插入图片描述
语法格式:父类类型 对象名 = new 子类类型()

public class Animal {public String name;public int age;public Animal(){}public Animal(String name,int age){this.name = name;this.age = age;}public void eat(){System.out.println(this.name + "正在吃饭");}public void bark(){System.out.println(this.name + "正在叫");}
}public class Cat extends Animal{public Cat(){}public Cat(String name,int age){super(name,age);}public void bark(){System.out.println(this.name + "正在喵喵叫");}
}public class Dog extends Animal{public Dog(){}public Dog(String name,int age){super(name, age);}@Overridepublic void bark() {System.out.println(this.name + "正在汪汪叫");}
}public class Main {public static void main(String[] args) {Animal animal = new Dog();//实现了向上转型animal.bark();}
}

观察上述代码,Cat 类和 Dog 类中都重写了 bark 方法,肯定有人觉得main 方法中的 bark 方法可有可无,当我们删除这个 bark 方法时,animal无法访问bark这个方法。
在这里插入图片描述
无法访问的原因是在Animal当中没有该方法,通过父类引用访问的时候,只能访问父类自己特有的,所以我们不能删除。

是不是在等向下转型,因为向下转型不常用,所以放在最后面了
在这里插入图片描述

3.2 发生向上转型的时机

  1. 直接赋值
public class Main {public static void main(String[] args) {Animal animal = new Cat("zaizai",2);}
}
  1. 方法传参的时候
public class Main {public static void func(Animal animal){}public static void main(String[] args) {func(new Cat());}
}
  1. 返回值的时候
public class Main {public static Animal func(){return new Cat() ;}public static void main(String[] args) {func();}
}

不是只有直接赋值一种哦,要注意啦
在这里插入图片描述

向上转型的优点:让代码的实现更加简单
向上转型的缺点:无法调用到子类特有的方法

4. 动态绑定和静态绑定

当父类引用子类的对象(即向上转型)时,通过父类引用、调用重写的方法就实现了动态绑定

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

静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
在这里插入图片描述

5. 什么是多态

5.1

回归正题,什么是多态呢
在这里插入图片描述
其实,上述代码就发生了多态,当 animal 引用的对象不一样,调用 eat 方法,表现的行为不一样,此时就叫多态。(同一个引用调用同一个方法表现的行为不一样

5.2 多态的优缺点

优点

  1. 降低圈复杂度(是一种用于评估代码复杂性的软件度量方法,代码的分支 / 判断越多,圈复杂度越高),避免使用大量的 if-else

例如:

public class Shape {public void draw(){System.out.println("画一个图形");}
}public class Rectangle extends Shape{@Overridepublic void draw() {System.out.println("画一个矩形");}
}public class Triangle extends Shape{@Overridepublic void draw() {System.out.println("画一个三角形");}
}public class Circle extends Shape {@Overridepublic void draw() {System.out.println("画一个圆");}
}public class Main {public static void drawMap(Shape shape){shape.draw();}public static void main(String[] args) {drawMap(new Triangle());drawMap(new Rectangle());drawMap(new Circle());}
}

例如,我们现在需要打印多个形状. 如果不基于多态, 实现代码如下

public static void drawMap() {Rectangle rectangle = new Rectangle();Triangle triangle = new Triangle();Circle circle = new Circle();String[] shapes = {"Rectangle","Circle","Circle","Triangle","Rectangle"};for(String shape:shapes){if(shape.equals("Rectangle"))rectangle.draw();else if(shape.equals("Circle"))circle.draw();else if(shape.equals("Triangle"))triangle.draw();}
}

基于多态

public static void drawMap(){Shape Rectangle = new Rectangle();Shape Triangle = new Triangle();Shape Circle = new Circle();Shape[] shapes = {Rectangle,Circle,Circle,Triangle,Rectangle};for(Shape shape:shapes){shape.draw();}}

果然基于多态方便了许多,没白学
在这里插入图片描述

不基于多态,圈复杂度高。基于多态,圈复杂度低,代码更简单。

  1. 可扩展性强
    当我们新增一个图形,创建一个新的实例就可以,改动代码较少。

缺点

  1. 属性没有多态性
    当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性

  2. 构造方法没有多态性

6. 避免在构造方法中调用重写的方法

当我们在构造方法中调用重写的方法的代码如下:

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

为什么会调用 D 的 func 方法呢?而且 num = 0 ,让我们来看一下它具体是怎么执行的
在这里插入图片描述

鸡爪子画图,宣!
在这里插入图片描述

步骤

  1. 构造D对象的同时,调用B的无参构造方法。
  2. B的构造方法中调用了 func 方法,此时触发动态绑定,调用 D 的 func 方法。
  3. 此时,D 对象自身还未构造,num 处于未初始化的状态,所以 num = 0

结论:尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题。

7. 向下转型在这里插入图片描述

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

例如:

Dog dog = (Dog)new Animal();

那么不强转为什么会报错呢?
我们可以理解为不是所有的动物都是狗,所以会报错。

但是向下转型非常不安全,例如

 Animal animal = new Cat();Dog dog = (Dog)new Animal();dog.bark();

虽然代码在编译层次上不会报错,但是运行结果为类型转换异常
在这里插入图片描述

Animal animal = new Cat();
Cat cat = (Cat)animal;
cat.bark();

因为animal引用的本身就是Cat对象,所以不会报错。

Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。

Animal animal = new Cat();
if(animal instanceof Cat){Cat cat = (Cat)animal;cat.bark();
}

上述语句表达的意思是,如果 animal 引用的是 Cat 类型……

虽然向下转型不安全,但是可以使用上述语句来解决问题。

终于完事了,我要奖励自己一下了
在这里插入图片描述

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

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

相关文章

HTML+CSS 水滴登录页

文章目录 一、效果演示二、Code1.HTML2.CSS 三、实现思路拆分 一、效果演示 实现了一个水滴登录页的效果。页面包含一个水滴形状的登录框和两个按钮&#xff0c;登录框包括用户名、密码和登录按钮&#xff0c;按钮分别为忘记密码和注册。整个页面的设计非常有创意&#xff0c;采…

一些超好用的 GitHub 插件和技巧

聊聊我平时使用 GitHub 时学到的一些插件、技巧。 ‍ ‍ 浏览器插件 在我的另一篇博客 浏览器插件推荐 里提到过跟 GitHub 相关的一些插件&#xff0c;这里重复下&#xff1a; Sourcegraph&#xff1a;在线打开项目&#xff0c;方便阅读&#xff0c;将 GitHub 变得和 IDE …

【AI创作组】Matlab中进行符号计算

提示:代码一定要自己运行过才算数…… 1. 符号计算工具箱介绍 1.1 工具箱功能 MATLAB的符号计算工具箱,即Symbolic Math Toolbox,是一套强大的数学软件工具,它使得MATLAB具备了符号运算的能力。该工具箱提供了一系列函数,用于求解、绘制和操作符号数学方程。用户可以直接…

【Linux】修改用户名用户家目录

0、锁定旧用户登录 如果旧用户olduser正在运行中是无法操作的&#xff0c;需要先禁用用户登录&#xff0c;然后杀掉所有此用户的进程。 1. 使用 usermod 命令禁用用户 这将锁定用户账户&#xff0c;使其无法登录&#xff1a; sudo usermod -L olduser2. 停止用户的进程 如…

Woocommerce怎么分类显示产品?如何将Shopify的产品导入到Woocommerce?

WooCommerce作为WordPress的一个电子商务插件&#xff0c;功能强大、使用简洁&#xff0c;能够轻松集成到WordPress网站中&#xff0c;为用户提供了一个完整的在线商店解决方案&#xff0c;在国外还是挺受欢迎的。 Woocommerce怎么分类显示产品&#xff1f; 在Woocommerce中&a…

【微服务】springboot 实现动态修改接口返回值

目录 一、前言 二、动态修改接口返回结果实现方案总结 2.1 使用反射动态修改返回结果参数 2.1.1 认识反射 2.1.2 反射的作用 2.1.3 反射相关的类 2.1.4 反射实现接口参数动态修改实现思路 2.2 使用ControllerAdvice 注解动态修改返回结果参数​​​​​​​ 2.2.1 注解…

docker pull 超时的问题如何解决

docker不能使用&#xff0c;使用之前的阿里云镜像失败。。。 搜了各种解决方法&#xff0c;感谢B站UP主 <iframe src"//player.bilibili.com/player.html?isOutsidetrue&aid113173361331402&bvidBV1KstBeEEQR&cid25942297878&p1" scrolling"…

已解决:“ModuleNotFoundError:No module named apex”

首先遇到这个问题不可以直接简单粗暴的使用&#xff1a;“pip install apex”直接安装模块来解决&#xff0c;这样的话程序还是会继续报错“ModuleNotFoundError&#xff1a;No module named apex”&#xff0c;别问我怎么知道&#xff0c;问就是深受其害&#xff01; 去网上查…

基于pdf.js实现对pdf预览、批注功能、 保存下载pdf,适配H5,平板 踩坑记录

项目场景&#xff1a; 在APP端实现对pdf的批注,能够下载保存.能够获取批注信息同时能够重新渲染到pdf中.基于pdf.js-4.5.136版本源码实现。pc端能够正常预览下载pdf&#xff0c;构建打包后嵌入uniapp的webview遇到的问题记录 问题描述 将构建打包后的代码嵌入到uniapp中&…

ELK-03-skywalking监控linux系统

文章目录 前言一、下载node_exporter二、启动node_exporter三、下载OpenTelemetry Collector四、启动OpenTelemetry Collector4.1 将配置文件下载到同级目录4.2 启动 五、查看总结 前言 skywalking安装完成后&#xff0c;开始我们的第一个监控-监控linux系统。 参考官方文档&a…

长列表加载性能优化

一、长列表优化概述 列表是应用开发中最常见的一类开发场景&#xff0c;它可以将杂乱的信息整理成有规律、易于理解和操作的形式&#xff0c;便于用户查找和获取所需要的信息。应用程序中常见的列表场景有新闻列表、购物车列表、各类排行榜等。随着信息数据的累积&#xff0c;特…

DMA的原理

一、介绍 DMA&#xff08;Direct Memory Access&#xff09;是一种允许设备直接与内存进行数据交换的技术&#xff0c;无需‌CPU干预。DMA的主要功能是提供在‌外设和存储器之间或者存储器和存储器之间的高速数据传输。比如使用ADC进行数据采集&#xff0c;可以直接将数据存入…

干货 | 2024制造业数字化现状调查白皮书(免费下载)

导读&#xff1a;在这本白皮书中&#xff0c;我们询问了制造商有关数字化转型的工作情况、2024 年的优先事项和可持续性。研究结果清楚地表明&#xff0c;在数字化方面处于领先地位的制造商转型项目比那些没有规划或刚刚起步的项目实现的价值要大得多。 加入知识星球或关注下方…

运维转型大模型:全面指南与实战总结

运维心里苦谁做谁知道&#xff0c;有时候感觉自己像一个杂工&#xff0c;在公司都快变成一个修电脑的了&#xff0c;不装了我转行了&#xff0c;给大家分享一点经验&#xff0c;希望能帮助到你们。 运维工程师转行至大模型领域需要学习一系列新的技能和知识。以下是一个详细的…

【算法】JAVA刷算法必备数据结构

文章目录 数组List队列和栈栈的应用&#xff1a;表达式求值 数组List ArrayList 类是一个可以动态修改的数组&#xff0c;与普通数组的区别就是它是没有固定大小的限制&#xff0c;我们可以添加或删除元素。 ArrayList 继承了 AbstractList &#xff0c;并实现了 List 接口。 …

Nest.js实现一个简单的聊天室

本文将介绍如何使用 Nest.js 和 Uni-app 实现一个简单的实时聊天应用。后端使用 nestjs/websockets 和 socket.io&#xff0c;前端使用 uni-app 并集成 socket.io-client。这个项目允许多个用户同时加入聊天并实时交换消息。 效果图&#xff1a; 一、准备工作 安装 Node.js 和…

DAF-Net:一种基于域自适应的双分支特征分解融合网络用于红外和可见光图像融合

论文 DAF-Net: A Dual-Branch Feature Decomposition Fusion Network with Domain Adaptive for Infrared and Visible Image Fusion 提出了一种新的红外和可见光图像融合方法。该方法旨在结合红外图像和可见光图像的互补信息&#xff0c;以提供更全面的场景理解。红外图像在低…

学习C++的第七天!

1.虚函数是在基类中用 virtual 关键字声明的函数&#xff0c;可以在派生类中被重写。纯虚函数是在虚函数的基础上&#xff0c;在基类中被初始化为 0 的函数&#xff0c;含有纯虚函数的类是抽象类&#xff0c;不能被实例化。 2.如果基类的析构函数不是虚函数&#xff0c;当通过…

现代cpp多线程与并发初探

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 在现代c(c20)中,有了jthread和协程的概念,使得我们编写并发程序更加方便. 这里作简单学习. 前言知识 多线程编程 std::thread 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 <thread…

Android个性名片界面的设计——约束布局的应用

节选自《Android应用开发项目式教程》&#xff0c;机械工业出版社&#xff0c;2024年7月出版 做最简单的安卓入门教程&#xff0c;手把手视频、代码、答疑全配齐 【任务目标】 使用约束布局、TextView控件实现一个个性名片界面的设计&#xff0c;界面如图1所示。 图1 个性名片…