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

目录

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

二、重写

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 nothingfunc();
}
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实际指向的是狗
// 现在要强制还原为猫,无法正常还原,运行时抛出:ClassCastExceptioncat = (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();
}
}
}

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

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

相关文章

zookeeper安装原生开发 C API接口时报错

报出的错误:error: %d directive writing between 1 and 5 bytes into a region of size be 问题原因 %d 格式说明符用于格式化有符号十进制整数。它需要一个与要格式化的整数大小相匹配的缓冲区。如果缓冲区太小,则会导致缓冲区溢出,从而可…

码头船只出行及配套货柜码放管理系统-毕设

毕业设计说明书 码头船只出行及配套货柜码放 管理系统 码头船只出行及配套货柜码放管理系统 摘要 伴随着全球化的发展,码头的物流和客运增多,码头业务迎来新的高峰。然而码头业务的增加,导致了人员成本和工作量的增多。为了解决这一基本问题&…

Redis篇:缓存更新策略最佳实践

前景: 缓存更新是redis为了节约内存而设计出来的一个东西,主要是因为内存数据宝贵,当我们向redis插入太多数据,此时就可能会导致缓存中的数据过多,所以redis会对部分数据进行更新,或者把他叫为淘汰更合适&a…

开放式耳机怎样选性价比高?五大性能出色爆款推荐!

在今年的耳机市场,开放式耳机如雨后春笋般涌现,为消费者提供了更多的选择。在这样一个产品繁多的市场中,如何挑选出一款音质上乘、性能卓越的开放式耳机,确实是一个值得探讨的问题。相较于长时间佩戴传统入耳式耳机可能带来的耳朵…

Jenkins 打包报错记录 error: index-pack died of signal 15

问题背景,打包每次到92%时就会报错,试了好几次都是同样的错误 14:56:53 fatal: index-pack failed 14:56:53 14:56:53 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:2734) 14:56:53 at org.jenkinsci.plugi…

【UE 材质】水波纹效果

效果 模拟雨水打落在水面上的效果 步骤 1. 下载所需纹理和纹理 纹理2. 新建一个材质,这里命名为“M_WaterRipples” 打开“M_WaterRipples”,添加一个纹理采样节点,纹理使用第一步下载的纹理 将纹理采样节点的R通道连接到基础颜色&#x…

MySQL、Oracle查看最大连接数和当前连接数

文章目录 1. MySQL2. Oracle 1. MySQL -- 查看最大连接数 show variables like max_connections; select max_connections; -- select * from performance_schema.session_variables where VARIABLE_NAME in (max_connections); -- select * from performance_schema.global…

产品推荐 | 基于Intel (Altera) Cyclone IV 打造的水星Mercury CA1核心板

01 产品概述 水星Mercury CA1核心板结合了Intel Cyclone IV FPGA、通用接口如USB 2.0和Gigabit Ethernet,具备大量的LVDS I/O、大容量DDR2 SDRAM和大量硬件乘法器,这些使得水星CA1核心板非常适合数字信号处理、网络、高速I/O以及使用Intel NiosII软处理…

某酒业集团数字化转型规划(169页附下载)

某酒业集团数字化转型项目实施方案建议书(P169).rar是一个极具参考价值的资料,它详细地阐述了如何利用数字化技术来推动企业转型。这份建议书以IBM的先进技术和某酒业集团的实际应用需求为基础,提出了一套全面、系统的数字化转型解决方案。该方案首先对某…

java体育馆使用预约平台的设计与实现(springboot+mysql源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的体育馆使用预约平台。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 体育馆使用预约平台的…

Win10 打开有些软件主界面会白屏不显示,其他软件都正常

环境: Win10专业版 英伟达4070 显卡 问题描述: Win10 打开有些软件主界面会白屏不显示,打开远程协助软件AIRMdesk,白色,其他软件都正常 解决方案: 网上说电脑没有接显示器独立显卡的关系导致 我是只有一台主机,没…

手撕netty源码(二)- 初始化ServerBootstrap

文章目录 前言一、ServerBootstrap 的创建和初始化1.1 创建1.2 初始化group1.3 初始化channel1.3 初始化option和attr1.4 初始化handler 和 childHandler 总结 前言 接上一篇:手撕netty源码(一)- NioEventLoopGroup 本篇讲解 ServerBootstra…

Vue

文章目录 Vue1. 创建Vue实例2. 插值表达式3. 响应式特性4. 常用指令4.1 内容渲染指令4.2 条件渲染指令4.3 事件绑定指令4.4 单向属性绑定指令4.5 双向属性绑定指令4.6 列表渲染指令 5. 修饰符5.1 事件修饰符5.2 键盘事件修饰符5.3 修饰符串联5.4 v-model 修饰符 6. computed计算…

Android SDK Manager安装Google Play Intel x86 Atom_64 System Image依赖问题

Package Google Play Intel x86 Atom_64 System Image,Android API R, revision 2 depends on SDK Platform Android R Preview, revision 2 问题 一开始以为网络还有依赖包没有勾选,尝试了很多次,勾选这边报错对应的license即可。此时点击一下其他licen…

CountDownLatch使用错误+未最终断开连接导致线程池资源耗尽

错误描述&#xff1a; 我设置了CountDownLatch对线程的协作做出了一些限制&#xff0c;但是我发现运行一段时间以后便发现定时任务不运行了。 具体代码&#xff1a; public void sendToCertainWeb() throws IOException, InterruptedException {List<String> urlList …

如何利用美国站群服务器实现有效的SEO优化策略?

如何利用美国站群服务器实现有效的SEO优化策略? 在当今数字化时代&#xff0c;SEO优化对于网站的可见性和吸引力至关重要。站群服务器作为一种有效的SEO策略&#xff0c;可以通过多个相关联的网站在不同服务器上的部署&#xff0c;增强网站的权威性和链接多样性。尤其是在利用…

ZYNQ之嵌入式开发04——自定义IP核实现呼吸灯、固化程序

文章目录 自定义IP核——呼吸灯实验固化程序 自定义IP核——呼吸灯实验 Xilinx官方提供了很多IP核&#xff0c;在Vivado的IP Catalog中可以查看这些IP核&#xff0c;在构建自己复杂的系统时&#xff0c;只使用Xilinx官方的免费IP核一般满足不了设计的要求&#xff0c;因此很多…

机器人自动驾驶时间同步进阶

0. 简介 之前时间同步也写过一篇文章介绍机器人&自动驾驶中的时间同步。在最近的学习中发现一些额外需要阐述学习的内容&#xff0c;这里就再次写一些之前没写到的内容。 1. NTP NTP 是网络时间协议&#xff0c;用来同步网络中各计算机时间的协议&#xff0c;把计算机的时…

品牌差异化战略:Kompas.ai如何打造独特的内容声音

在当今竞争激烈的商业环境中&#xff0c;品牌差异化已成为企业获取市场优势的关键策略。一个鲜明的品牌形象和独特的内容声音不仅能够帮助企业吸引目标客户&#xff0c;还能够在消费者心中建立起独特的地位。本文将深入探讨品牌差异化的重要性&#xff0c;分析Kompas.ai如何帮助…

揭秘 IDM:下载管理大师的全面指南与实用技巧深度解析

IDM&#xff08;Internet Download Manager&#xff09;是一款流行的下载管理软件&#xff0c;它可以帮助用户以更快的速度下载文件&#xff0c;并且支持多种协议和浏览器。IDM 通过将大文件分割成多个部分并同时下载这些部分来加快下载速度&#xff0c;这种技术被称为多线程下…