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

news2024/10/7 6:39:24

目录

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

二、重写

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();
}
}
}

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

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

相关文章

万兆以太网MAC设计(8)ICMP协议详解以及ICMP层模块设计

文章目录 前言:ICMP协议详解一、ICMP_RX模块二、ICMP_TX模块三、仿真总结 前言:ICMP协议详解 ICMP (Internet Control Message Protocol) 协议被设计用来向 IP 源端报告差错及其它相关信息, IP 协议本身只设置有 Checksum 机制来保证数据的正确性, 它本身…

个人搭建alist网盘的经验记录备忘

1、搭建宝塔LINUX面板,安装Docker 2、添加仓库 3、从镜像拉取xhofe/alist:latest 4、添加容器 5、新建一个网站,别忘记申请个SSL证书,重要的是反向代理 6、新建个mysql数据库 7、修改alist数据库的链接地址,方便自己备份&a…

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

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

第一讲 - Java入门

第一讲 - Java入门 文章目录 第一讲 - Java入门1. 人机交互1.1 什么是cmd?1.2 如何打开CMD窗口?1.3 常用CMD命令1.4 CMD练习1.5 环境变量 2. Java概述1.1 Java是什么?1.2下载和安装1.2.1 下载1.2.2 安装1.2.3 JDK的安装目录介绍 1.3 HelloWor…

python——飞机大战游戏(下载模块,知识点,图片)

飞机大战——准备工作 这篇文章我们只有关于pygame模块的下载,和一些知识点,还有飞机大战我们需要用到的图片。下一篇文章我们进行代码的详细解析。 1.1安装pygame模块 方法一: 在pycharm中打开命令行下载,输入pip install py…

Axure设计美观友好的后台框架页

使用Axure设计后台框架页 优点介绍: **1、使用中继器灵活配置菜单项; 2、二级菜单面板跟随一级菜单位置显示; 3、菜单链接打开后,联动添加tab标签; 4、标签页与iframe内容联动,可关闭; 5、左侧…

linux 定位进程文件路径

有时候用top 打开任务管理器时知道某个任务的进程的存在&#xff0c;但不知道是哪个文件&#xff0c;只需两条指令只可定位进程的可执行文件路径 使用 ls -l /proc/<PID>/cwd 命令来查找该进程的当前工作目录。使用 cat /proc/<PID>/cmdline 命令来查看该进程的命…

富集分析不求人,零代码可视化GO/KEGG分析结果

01 爱基百客云平台小工具使用 首先&#xff0c;打开爱基百客官网&#xff1a;http://www.igenebook.com&#xff1b;点击菜单栏最右侧“云平台”按钮。 弹出云平台界面&#xff08;下图&#xff09;&#xff0c;输入账号、密码和验证码方可登录&#xff1b;进入云平台&#xf…

ThingsBoard服务端使用RPC通过网关给设备发送消息

一、概述 1、发送服务器端网关RPC 二、案例&#xff1a; 1、建立设备与网关之间的通讯 2、查看设备和网关是否在线状态啊 3、通过 仪表盘&#xff0c;创建设备A的模拟RPC调用的窗口链接 4、在客户端的网关设备上订阅RPC网关的主题信息 5、通过服务端的窗口&#xff0c;发…

JavaEE >> Spring(2)

前面已经介绍了 Spring 的基本使用以及创建&#xff0c;本文将介绍使用注解的方式实现对 Spring 更简单的存储对象和读取对象. 将对象存储到 Spring 中 创建 Spring 项目 前面已经做过详细步骤&#xff0c;此处不再赘述. 链接在此 Spring 基本使用及创建 pom.xml 和 Spring…

机器学习模型效果不好及其解决办法

当训练出来的机器学习模型效果不佳时&#xff0c;可能涉及多个方面的原因。为了改善模型的效果&#xff0c;需要系统地检查和分析问题的根源&#xff0c;并采取相应的措施进行优化。 一、数据问题 数据质量 检查数据是否干净、完整&#xff0c;是否存在噪声、异常值或缺失值。…

【后端】python2和python3的安装与配置

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、python是什么二、python环境的安装与配置Python 2的安装与配置Python 3的安装与配置注意事项 三、总结 前言 随着开发语言及人工智能工具的普及&#xff0…

C++ //练习 13.17 分别编写前三题中所描述的numbered和f,验证你是否正确预测了输出结果。

C Primer&#xff08;第5版&#xff09; 练习 13.17 练习 13.17 分别编写前三题中所描述的numbered和f&#xff0c;验证你是否正确预测了输出结果。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /*************************…

git提交注释规范插件

1、前言 为什么要注重代码提交规范&#xff1f; 在团队协作开发时&#xff0c;每个人提交代码时都会写 commit message。 每个人都有自己的书写风格&#xff0c;翻看我们组的git log, 可以说是五花八门&#xff0c;十分不利于阅读和维护。 一般项目开发都是多分支共存&#x…

浅涉ROS世界中的坐标系及其他

声明&#xff1a;文中图片素材均采用了其他博主文章&#xff08;文末参考来源&#xff09;&#xff0c;如有侵权或不妥&#xff08;确有不妥和不安&#xff0c;奈何苦于佳图难觅&#xff09;&#xff0c;还望告知&#xff0c;立即删除&#xff01; 坐标系统 ROS中的…

影视后期特效合成:DaVinci Fusion Studio19 激活版

DaVinci Fusion Studio是一款功能强大的影视后期特效合成软件&#xff0c;可广泛应用于视觉效果、广播电视设计、动态图形设计、3D动画设计等领域。 如综合的绘图、动态掩蔽、遮片、图层叠加、字幕等工具&#xff0c;结合高效的粒子生成系统&#xff0c;通过它可以创建各种精细…

51单片机入门_江协科技_35~36_OB记录的自学笔记_AD与DA转换(XPT2046)

35. AD_DA 35.1. AD/DA介绍 •AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号 •DA&#xff08;Digital to Analog&#xff09;&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换…

【Word中如何对比文档修改前后的不同之处】

1、准备两个word文档&#xff08;一个是修改前文档&#xff0c;一个是修改后文档&#xff09; 2、双击打开两个文档&#xff0c;点击【审阅】-【比较】-选择修改前的文档和修改后的文档-【确定】&#xff0c;进入文档比较界面。 3、在比较结果文档中&#xff0c;可以查看修改前…

杰出贡献!51Sim助力ASAM新版本智驾标准发布

日前&#xff0c;ASAM&#xff08;德国自动化及测量系统标准协会&#xff09;正式发布了自动驾驶仿真场景标准OpenSCENARIO XML V1.3.0和OpenSCENARIO DSL V2.1.0&#xff0c;这两项标准是自OpenSCENARIO标准版本V1及V2拆分为两个独立标准以来首次正式发布。 作为ASAM会员单位…

stripe.js踩坑日记

stripe.js踩坑日记 先附上代码【选择支付方式并唤起对应支付后重定向到支付结果页面】 先安装依赖包 npm install stripe/stripe-js代码【vue3语法】 <template><div class"stripe-pay-ment-box"><div id"payment-element"></div…