Java继承和多态(2)

🐵本篇文章将对多态的相关知识进行讲解


一、向上转型

向上转型是实现多态的条件之一;向上转型是让子类对象转换为父类对象或者是让父类的引用指向子类对象,直观的表现形式就是将子类的对象赋值给父类对象的引用;下面讲解向上转型的三种形式

1.1 直接赋值

class Animal { }
class Dog extends Animal { }

public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog(); //向上转型
    }
}

1.2 传参

class Animal {}
class Dog extends Animal {}

public class Test {
    public static void func(Animal animal) { //发生向上转型
        animal.eat();
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        func(dog); //将Dog对象传过去,在func方法中用父类对象接收
    }
}

1.3 返回值

class Animal {}
class Dog extends Animal {}

public class Test {
    public static Animal func() { 
        return new DOg(); //发生向上转型
    }
    public static void main(String[] args) {
        Dog dog = new Dog();
        func(); 
    }
}

注意:向上转型后父类对象并不能访问子类中特有的成员方法

1.4 向下转型

直接看代码:

class Animal {
    public void eat() {
        System.out.println("吃");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗在吃");
    }
    public void barks() {
        System.out.println("狗在叫");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.eat();
        //animal.barks();//向上转型后,animal也不能访问子类独有的成员方法,但是可以进行向下转型
        
        Dog dog = (Dog) animal; //将父类对象强转为子类对象
        dog.barks(); //此时就可以访问子类独有的成员方法
    }
}

向下转型也存在一些危险,在上述代码的基础上再增加一个鸟类:

class Animal {
    public void eat() {
        System.out.println("吃");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗在吃");
    }
    public void barks() {
        System.out.println("狗在叫");
    }
}

class Bird extends Animal {
    public void fly() {
        System.out.println("鸟在飞");
    }
    public void eat() {
        System.out.println("鸟在吃");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();
        
        Bird bird = (Bird) animal;
        bird.fly(); //编译不会报错,但在运行时会报错,
                    //因为animal实际引用的是一个狗的对象,只能强转为一个狗类
       

        //为了避免这种情况的发生,引入instanceof关键字
        if (animal instanceof Bird) { //这条语句的意思就是animal所指的对象是否为鸟类
            Bird bird1 = (Bird) animal;
            bird1.flu //运行时不会报错
        }
    }
}

二、方法的重写

方法的重写也是也是实现多态的条件之一,重写也叫覆盖,方法的重写发生在继承关系下,一般称作子类对父类的方法进行重写,即在子类中再写一个方法,这个方法必须和父类那个方法的方法名、参数列表、返回值类型相同;这里可以和方法的重载比较理解

重载:方法名相同,参数列表不同,与返回值类型无关

重写:方法名相同,参数列表相同,返回值类型相同

class Animal {
    public void eat() {
        System.out.println("吃");
    }
}

class Dog extends Animal {

    //重写的方法可以用@Override来注释,这样在编译时可以多一层校验
    //如果加上这条注释后,eat方法没有进行重写,那么在编译时就会报错
     @Override
    public void eat() { //方法名都为eat,返回值类型都为void,参数列表相同
        System.out.println("狗在吃");
    }
}

2.1 重写的注意事项

1. 被final修饰的方法叫做密封方法,此方法不能被重写

class Animal {
    public final void eat() {
        System.out.println("吃");
    }
}

class Dog extends Animal {
    
    @Override
    public void eat() {
        System.out.println("狗在吃");
    }
}

//编译会报错,因为父类eat方法被final修饰,eat方法不能被重写

2. 被static修饰的方法不能被重写

3. 子类重写父类方法时,子类方法的访问限定修饰符必须大于等于父类方法,但如果父类方法被private修饰,那么该方法就不能被重写

4. 重写的方法的返回值类型也可以不同,但必须构成父子类关系

class Animal {
    public Animal eat() {
        System.out.println("吃");
        return null; //这里是为了不报错才这么写的
    }
}

class Dog extends Animal {
    @Override 
    public Dog eat() {
        System.out.println("狗在吃");
        return null;
    }
}

2.2 动态绑定

当一个子类对象被转换为了父类对象(向上转型),如果该对象调用一个在子类中被重写的父类方法,Java会根据子类的实际类型来调用子类对象实际所属类的方法,这个过程叫做动态绑定,动态绑定并不是在编译时就知道调用哪一个方法,而是在运行时才知道真正要调用哪一个方法

2.3 构造方法中避免调用重写方法

在构造方法中如果调用重写方法也会发生动态绑定

class B {
    public B() {
        func(); //这里会调用子类的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); //这里打印的num为0
    }
}

public class Test2 {
    public static void main(String[] args) {
        D d = new D();
    }
}

为什么num打印结果为0?先来回顾以下的执行顺序

父类静态--->子类静态--->父类实例--->父类构造--->子类实例--->子类构造

在上述代码中完成父类构造后,直接调用func方法,没有执行子类实例,也就是此时num并没有被赋值,是默认值0

三、多态

多态就是一个父类引用在调用重写的方法时,根据引用所指的对象不同,而调用的不同的方法,以下面的代码为例:

class Animal {
    public void eat() {
        System.out.println("吃");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗在吃");
    }
}

class Bird extends Animal {
    public void eat() {
        System.out.println("鸟在吃");
    }
}

public class Test {
    
    public static void func(Animal animal) {
        animal.eat(); //我们称在这里发生了多态
    }
    public static void main(String[] args) {
        Dog dog = new Dog();
        Bird bird = new Bird();
        
        func(dog);
        func(bird);
    }
}

总结:必须向上转型后才能实现动态绑定,通过动态绑定调用子类重写方法,而多态完成了很多次的动态绑定

3.1 多态的好处

1. 可以避免代码中的圈复杂度(即代码中条件语句和循环语句出现的次数)

2. 可扩展性强

class Shape {
    public void draw() {
        System.out.println("画图形");
    }
}

class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("圆形");
    }
}

class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("矩形");
    }
}

class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("三角形");
    }
}
public class Test2 {
    public static void main(String[] args) {
        Cycle cycle = new Cycle();
        Rect rect = new Rect();
        Triangle triangle = new Triangle();

        Shape[] shapes = new Shape[]{cycle, rect, cycle,rect,triangle}; //发生向上转型
        for(Shape shape: shapes) {
            shape.draw(); 发生多态,如果不使用多态,就要用到大量if-else,使代码的圈复杂度提高
        }
        //结果为:圆形 矩形 圆形 矩形 三角形
    }
}

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

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

相关文章

gdb详解【Linux知识贩卖机】

你背朝太阳,就只能看到自己的影子。 --纪伯伦语录 文章目录 简介准备常用命令查看代码(list)运行(run)打断点(break)逐语句(step)逐过程(next)完成…

电源管理芯片知识分享:电源芯片的特点及故障检测方法

电源管理芯片用于对电源的控制和管理,提高设备的性能,被广泛应用于智能家居、电子商务、能源管理、汽车等领域,是现代电子设备不可缺少的部分。因此,对于电源管理芯片的检测也是十分重要的,发现其故障并及时解决&#…

MySQL8.0学习笔记

1. CMD命令 1.1 数据库启动与停止 (1) 启动数据库:net start mysql80 (2) 停止数据库:net stop mysql80 1.2 数据库连接与退出 (1) 连接数据库:mysql [-hlocalhost -P3306] -uroot -p[123456] // 本地数据库可省略-h -P (2) 退出数据库…

2023年亚太杯数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模…

Leetcode刷题详解——太平洋大西洋水流问题

1. 题目链接:417. 太平洋大西洋水流问题 2. 题目描述: 有一个 m n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。 这个岛被分割成一个由若干方形单元格…

B : 赫夫曼编码长度

Description 每行一个大小写英文字母组成的字符串,长度不大于 1000,通过前缀编码后最短的编码长度。 Input 每组数据一行,大小写英文字母 Output 每组数据输出赫夫曼编码长度 Sample 思路: string res "";//用于…

市场火爆的AI实景自动直播是什么?一文带你了解清楚!

最近AI实景自动直播在各大短视频平台爆火出了新高度,在如今全民直播的时代,直播已经成为大多数商家商家必须要会的技能,包括全国头部品牌也在纷纷加码直播,甚至早早就开启了直播矩阵的玩法,中腰部商家也在考虑如何入手…

【3】Spring Boot 3 集成mybatis-plus+druid+mysql

目录 【3】Spring Boot 3 集成组件:Druid Mybatis Plus Mysql集成方案1. Hikari jdbc mysql 集成方案增加依赖添加配置Spring Testng 测试用例 2. Druid Mybatis Plus Mysql集成方案2.1 配置Druid添加依赖配置启动Spring Boot Web StarterSpring Testng测试用…

Linux开发工具03:使用GCC、make和CMake编译代码

写在前面 这里主要记录一下如何使用GCC、make和CMake编译代码; 一、GCC g是GCC下专门用于编译C项目的编译器; 假设目录结构如下: include:包含分离的.h和.cpp文件;src:包含主函数入口main.cpp&#xff1…

双点重发布+路由策略实验

一、双点重发布实验 1、实验拓扑图 2、各路由器IP地址、环回地址配置 R1 R2 R3 R4 3、启动RIP和OSPF 4、双向重发布 5、查看路由信息 6、更改网络类型 6、抓取流量 二、路由策略实验 1、实验拓扑图 2、各路由器IP地址的配置 3、启动RIP和OSPF 3、重发布 4、抓取流量 5、创建…

电脑屏幕标记软件——Pointofix

前言 Pointofix是一款由德国人开发的屏幕标记软件,德国人的工匠精神,是出了名的,德国人开发的软件也一样。 Pointofix体积非常小巧,安装包只有1MB大小,使用Pointofix可以直接在屏幕上面写字、画图、标重点。 下面介…

为什么Springboot项目中有些写法继承了SpringBootServletInitializer类?Springboot的两种发布方式

文章目录 一、前言二、SpringBoot的两种发布方式2.1、内置容器运行2.2、外置容器(Tomcat)运行 三、扩展3.1、如何将 Spring Boot 项目打包成 war 包? 一、前言 在一次SpringBoot源码中看到了启动类中继承了SpringBootServletInitializer&…

数据结构-二叉树的前、中、后序遍历

目录 1. 二叉树的遍历 1.1 前序 1.2 中序 1.3 后序 1.4 遍历的复杂度 2.二叉树节点个数及高度的计算 2.1 二叉树节点个数 2.2 二叉树叶子节点的个数 2.3 二叉树高度 2.4 二叉树第k层节点个数 1. 二叉树的遍历 前面的章节中,我们学习了二叉树的顺序结构&am…

Python入门:一文详解Python列表(List)操作方法

文章目录 前言一、创建一个列表二、访问列表中的值三、更新列表四、删除列表元素六、Python列表截取七、Python列表操作的函数和方法关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②…

【thop.profile】thop.profile计算网络参数量和计算效率

🍋🍋1.安装thop 安装thop有两种方式。 🏆第一种 pip install thop 🏆第二种 用源码编译安装 从官网下载【github】thop安装压缩包下载压缩文件,解压到虚拟环境的site-packages文件下激活进入自己的虚拟环境cd到压缩…

不同类型的软件企业该如何有效的管理好你的软件测试团队?

最近在网上发现一篇记录了2012年《[视频]作为测试经理如何有效管理好你的软件测试团队》的文字内容,感谢记录的人,我也保存一下。顺便将演讲中的PPT重点截图也放上来,一并保存了!。由于是现场速记,过度的口语化&#x…

迅为iTOPRK3588开发板系统定制(无法联网)

在上一个小节中讲解了 ubuntu 和 debian 文件系统的定制,但那是在可以运行脚本正常构 建系统的前提下,而本小节则是针对部分特殊用户无法联网的情况。 在 source 目录下存放了已经构建完成的压缩包,如下图所示: 然后使用以下命令…

weblogic控制台登陆console的时候慢

我们在搭建完weblogic后,登录控制台时,会出现等待很长时间的情况。 如下图:怎么解决呢 连接所属服务器,.找到jdk的安装路径 [rootlocalhost lib]# echo $JAVA_HOME/ /usr/java/jdk1.8.0_161/ 进入jre下的lib目录下的security目录&#xff0…

全球市场的新趋势:海外网红营销和私域流量的共同驱动

在数字时代的今天,随着全球互联网的蓬勃发展,网络营销已经不再是一种新鲜事物。然而,随着社交媒体和在线内容创作的兴起,一种新的营销方式崭露头角,它将海外网红营销与私域流量相结合,成为了全球市场的一股…

刘家窑中医院医生王忠:以仁心诠释医者使命

王忠是刘家窑中医院的一名医生,从医多年,积累了丰富的临床经验,挽救了无数病人的生命。他以“想病人之所想,急病人之所急”为自己行医济世的人生格言。 病人说:他是一位可亲可敬的“亲人”。 “医以德为本&#xff0c…