重学java 24.面向对象 多态

news2024/11/17 6:52:34

下雨了,跑不跑衣服都会被淋湿,还不如慢慢地走,结局已定

                                                                                      —— 24.4.25

多态

1.面向对象三大特性:封装        继承        多态

2.怎么学:

        a、不要从字面意思上理解多态这两个字,要从使用形式上掌握

        b、要知道多态的好处

        c、要知道多态的前提(什么样的情况下才能形成多态)

一、多态的介绍和基本使用

1.前提:

        a、必须有子父类继承或者接口实现关系

        b、必须有方法的重写(没有重写,多态没有意义),多态主要是调用重写方法

        c、new对象:父类引用指向子类对象

                Fu fu = new Son() -> 理解为大类型接收了一个小类型的数据 -> 比如:double b = 10

2.注意:

        多态下不能直接调用子类特有功能

3.基本使用

抽象类

public abstract class Animal {
    public abstract void eat();
}

子类1

public class Dog extends Animal{

    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    // 特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}

子类2

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 特有方法
    public void catchmouse(){
        System.out.println("猫会抓老鼠");
    }
}

测试类

public class Demo122Test {
    public static void main(String[] args) {
        // 原始方法
        Dog dog = new Dog();
        // 重写的方法
        dog.eat();
        // 特有的方法
        dog.lookDoor();

        Cat cat = new Cat();
        // 重写的方法
        cat.eat();
        // 特有的方法
        cat.catchmouse();

        System.out.println("——————————————————————");
        // 多态形式new对象
        Animal animal = new Dog();// 相当于double b = 10
        // 重写的animal,接受的是dog对象,所以调用的是dog里的eat方法
        animal.eat();
//        animal.loolDoor();    多态前提下,不能直接调用子类特有成员

        Animal animal1 = new Cat();
        // cat重写的方法
        animal1.eat();

    }
}

二、多态的前提下成员访问特点

成员变量

父类

public class Fu {
    int num = 1000;
}

子类

public class Son extends Fu{
    int num = 100;
}

测试类

public class Demo123Test {
    public static void main(String[] args) {
        Fu fu = new Son();
        System.out.println(fu.num);
    }
}

成员变量看等号左边是谁,先调用谁中的成员变量

成员方法

父类

public class Fu {
    int num = 1000;
    public void method(){
        System.out.println("父类中的method方法");
    }
}

子类

public class Son extends Fu{
    int num = 100;

    public void method(){
        System.out.println("我是子类中重写的method方法");
    }
}

测试类

public class Demo123Test {
    public static void main(String[] args) {
        Fu fu = new Son();
        System.out.println(fu.num);// 父类中的num
        fu.method();// 我是子类中重写的method方法
    }
}

成员方法看new的是谁,先调用谁中的成员方法,子类没有找父类

三、多态的好处

1.问题描述:

        如果使用原始方式new对象等号左右两边一样),既能调用重写的,还能调用继承的,还能调用自己特有的成员

        但是多态方式new对象,只能调用重写的,不能直接调用子类特有的成员,那为啥还要用多态呢

2.多态方式和原始方式new对象的优缺点:

        原始方式:

                a、优点:既能调用重写的,又能调用继承的,还能调用自己特有的成员

                b、缺点:扩展性差,尤其是方法的参数传递

        多态方式:

                a、优点:扩展性强(父类可以接收其任意的子类)

                b、缺点:不能直接调用子类特有的功能

                        Fu fu = new Son();

                        double b = 10;

                        b = 100L;

形参传递父类类型,调用此方法父类型可以接收任意它的子类对象
传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法

示例:

animal

public abstract class Animal {
    public abstract void eat();
}

cat

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 特有方法
    public void catchmouse(){
        System.out.println("猫会抓老鼠");
    }
}

dog

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

    // 特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}

test1

public class Demo124Test1 {
    public static void main(String[] args) {
        Dog dog = new Dog();
//      重写的方法
        dog.eat();
//      特有的方法
        dog.lookDoor();

        System.out.println("————————————————————");
        method(dog);

        Cat cat = new Cat();
        method(cat);
    }

    public static void method(Dog dog){
        dog.eat();
        dog.lookDoor();
    }

    public static void method(Cat cat){
        cat.eat();
        cat.catchmouse();
    }
}

test2

public class Demo125Test2 {
    public static void main(String[] args) {
        // 父类接收子类类型
        Animal animal = new Dog();
        animal.eat();

        animal = new Cat();
        animal.eat();

        // 传统方式接受类型
        Dog dog = new Dog();
        method(dog);

        Cat cat = new Cat();
        method(cat);
    }

    // 形参传递父类类型,调用此方法父类型可以接收任意它的子类对象
    // 传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法
    public static void method(Animal animal){
        animal.eat();
    }
}

四、多态中的转型

1.向上转型

父类引用指向子类对象

        好比是:double b = 1;

2.向下转型

① 好比强转,将大类型强制转换成小类型

② 表现方式:

        父类类型 对象名1 = new 子类对象() ——> 向上转型 ——> double b = 1

        子类类型 对象名2 = (子类类型)对象名1 ——> 向下转型 ——> int i = (int)b

③ 想要调用子类特有的功能,我们就需要向下转型

3.案例

父类animal

public abstract class Animal {
    public abstract void eat();
}

子类cat

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 特有方法
    public void catchmouse(){
        System.out.println("猫会抓老鼠");
    }
}

子类dog

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

    // 特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}

测试类

public class Demo126Test01 {
    public static void main(String[] args) {
        // 多态new法
        Animal animal = new Dog();
        animal.eat();// dog重写的
        /*
        animal.lookDoor();// 多态不能调用子类特有功能
        */
        // 向下转型 强转 就可以调用子类的特有功能
        Dog dog = (Dog) animal;
        dog.eat();
        dog.lookDoor();
    }
}

五、转型中可能出现的问题

1.类型转换异常(ClassCastException)

        如果等号左右两边类型不一致,则会出现类型转换异常(ClassCastException

                原因:当调用method传递Cat对象时,animal代表的就是cat对象
                此时,我们将代表cat对象的animal强转成了animal
                此时等号左右两边类型不一致了,所以出现了类型转换异常

public class Demo128Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        method(dog);

        System.out.println("——————————————————————————");
        Cat cat = new Cat();
        method(cat);
    }

    public static void method(Animal animal){
        // animal = dog
        // animal = cat
        animal.eat();

        /*
          这里会出现类型转换异常
          ClassCastException
          原因:当调用method传递Cat对象时,animal代表的就是cat对象
          此时,我们将代表cat对象的animal强转成了animal
          此时等号左右两边类型不一致了,所以出现了类型转换异常
         */
        Dog dog = (Dog) animal;
        dog.lookDoor();
    }
}

2.解决:

        在向下转型之前,先判断类型

3.判断类型的方法:

        instanceof

        判断结果是boolean型

4.使用

        对象名 instanceof 类型 ——> 判断的是关键字前面的对象是否符合关键字后面的类型

5.示例

public class Demo128Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        method(dog);

        System.out.println("——————————————————————————");
        Cat cat = new Cat();
        method(cat);
    }

    public static void method(Animal animal){
        // animal = dog
        // animal = cat
        // animal.eat();

        /*
          这里会出现类型转换异常
          ClassCastException
          原因:当调用method传递Cat对象时,animal代表的就是cat对象
          此时,我们将代表cat对象的animal强转成了animal
          此时等号左右两边类型不一致了,所以出现了类型转换异常
         */
        // Dog dog = (Dog) animal;
        // dog.lookDoor();

        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.eat();
            dog.lookDoor();
        } else if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.eat();
            cat.catchmouse();
        }
    }
}

六、综合练习

案例要求:       

        定义笔记本类,具备开机,关机和使用USB设备的功能。具体是什么USB设备,笔记本并不关心,只要符合USB规格的设备都可以。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,不然鼠标和键盘的生产出来无法使用;进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
USB接口,包含开启功能、关闭功能
笔记本类,包含运行功能、关机功能、使用USB设备功能
鼠标类,要符合USB接口
键盘类,要符合USB接口

定义USB接口:

public interface USB {
    // 开启功能
    public abstract void Open();

    // 关闭功能
    public abstract void Close();
}

笔记本类:

        接收USB接口和鼠标类键盘类对接口的具体实现,然后进行方法的定义,私有方法对接收的类用instanceof进行判断,然后不同类型不同实现

public class NoteBook {
    // 开机
    public void Start(){
        System.out.println("笔记本在运行");
    }

    // 关机
    public void Close(){
        System.out.println("笔记本关机");
    }

    // 关机
    /*
        USB usb = mouse 多态
        USB usb = keyBoard 多态
     */
    public void UseUSB(USB usb){
        if(usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;
            mouse.Open();
            mouse.click();
            mouse.Close();
        } else if (usb instanceof KeyBoard) {
            KeyBoard keyBoard = (KeyBoard) usb;
            keyBoard.Open();
            keyBoard.input();
            keyBoard.Close();
        }
//        usb.Open();
//        usb.Close();
//        System.out.println("使用USB功能");
    }
}

定义鼠标类,符合USB接口

        继承USB父类接口进行鼠标类Mouse具体的实现

public class Mouse implements USB {
    @Override
    public void Open() {
        System.out.println("鼠标开启");
    }
    @Override
    public void Close() {
        System.out.println("鼠标关闭");
    }

    // 特有方法
    public void click(){
        System.out.println("点击鼠标");
    }
}

定义键盘类,符合USB接口

        继承USB父类接口进行键盘类KeyBoard具体的实现

public class KeyBoard implements USB{
    @Override
    public void Open() {
        System.out.println("键盘开启");
    }

    @Override
    public void Close() {
        System.out.println("键盘关闭");
    }

    // 特有功能
    public void input(){
        System.out.println("敲击键盘");
    }
}

测试类

public class Demo129Test {
    public static void main(String[] args) {
        NoteBook noteBook = new NoteBook();
        Mouse mouse = new Mouse();
        noteBook.Start();
        // 多态的使用
        noteBook.UseUSB(mouse);
        noteBook.Close();

        System.out.println("——————————————————");
        KeyBoard keyBoard = new KeyBoard();
        noteBook.Start();
        // 多态的使用
        noteBook.UseUSB(keyBoard);
        noteBook.Start();
    }
}

运行结果

七、总结

1.接口

概述

        是一种引用数据类型,是一个标准,规则

⭐定义

        a、定义接口 —— public interface 接口名{}

        b、实现接口 —— public class 实现类 implements 接口{}

⭐抽象方法

        a、定义 —— public abstract 返回值类型 方法名(形参);

        b、使用 —— 实现类实现接口

                      —— 重写抽象方法

                      —— 创建实现类对象,调用重写方法 —— 接口不能new对象

默认方法

         a、定义 —— public default 返回值类型 方法名(形参){

                                       方法体;

                                       return;

                                }

         b、使用 —— 在实现类中可重写,可不重写

                       —— 创建实现类对象,调用默认方法

静态方法

        a、定义 —— public static 返回值类型 方法名(形参){

                                      方法体;

                                      return 结果;

                              }

        b、使用 —— 接口名直接调用

成员变量

        a、定义 —— public static final 数据类型 变量名 = 值

        b、使用 —— 接口名直接调用

⭐接口的特点

        a、接口可以多继承

        b、接口可以多实现

        c、一个类可以继承一个父类的同时实现一个或多个接口

接口的抽象类的区别

        a、相同点

                ① 都位于继承顶端,用于被其他类继承或者实现

                ② 都不能new

                ③ 都包含抽象方法,而且必须重写

        b、不同点

                ① 抽象类:一般作为父类使用,可有成员变量,构造方法,成员方法,抽象方法等

                ② 接口:成员单一,一般抽取接口,都是方法

                ③ 类不能多继承,接口可以

⭐2.多态

前提

        a、必须有子父类继承关系或者接口实现关系

        b、必须有方法的重写

        c、父类引用指向子类对象

成员访问特点

        a、成员变量 —— 看等号左边是谁

        b、成员方法 —— 看new的是谁

特点

        a、优点 —— 拓展性强

        b、缺点 —— 不能直接调用子类特有功能

转型

        a、向上转型 —— 父类引用指向子类对象

        b、向下转型 —— 将父类类型转成子类类型 —— 调用子类特有功能

        c、类型转换异常 —— ClassCastException

        d、类型判断 —— 对象名 instanceof —— 判断对象是否属于指定的类型

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

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

相关文章

【Redis 开发】Redis哨兵

哨兵 作用和原理服务状态监控选举新的master 搭建哨兵集群RedisTemplate的哨兵模式 作用和原理 Redis提供了哨兵机制来实现主从集群中的自动故障恢复: 哨兵也是一个集群 监控:会不断检查master和slave是否按预期工作自动故障恢复:如果mast…

开发工具-pycharm的代码自动部署服务器以及服务端python配置、项目开发环境一键启动服务

文章目录 一、pycharm的ssh配置1.本地生成ssh密钥2.密钥配置到远端服务器(1-1) 有权限ssh访问到服务器(1-2) 无权限ssh访问到服务器(1-3) 没有办法通过以上形式上传到服务器(2) 配置到authorized_keys自动访问 3.pycharm中配置ssh(1) 选择File中的settings(1) 选择Tools中的SSH…

Github创建远程仓库(项目)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

StarBright染料--星光高亮抗体 助力多色方案

星光染料是一种独特的荧光纳米粒子,将它与 Bio-Rad 高度验证的抗体结合,专为流式细胞术开发,为您提供卓越染色效果。星光染料使稀有群体和低密度抗原易于分辨,同时保持适用于任何多色实验的灵活性。 本篇将帮助你了解高亮星光染料…

springboot权限验证学习-下

上篇讲了rbac对于菜单的权限,下面准备完成按钮权限以及行数据和列数据权限 权限控制(按钮权限) 权限控制 操作权限就是将操作视为资源,比如删除操作,有些人可以有些人不行。于后端来说,操作就是一个接口。于前端来说&#xff0…

vue2使用change事件监听不了回车事件的问题

在 vue2 项目中使用 el-input 的 change 监听&#xff0c;数据不发生变化时&#xff0c;回车事件和失去焦点不生效 输入框会一直显示 只有数据发生变化时才生效 <el-input v-model"editedText" change"endEditing" ref"input"></el-inp…

校园广播系统:智能化管理提升校园安全与效率

在现代教育环境中&#xff0c;校园广播系统不再仅仅是一个播放音乐和通知的工具&#xff0c;它已经成为学校基础设施中不可或缺的一部分。根据《义务教育阶段学校信息化设备配备标准》的第8条&#xff0c;校园广播系统在学校范围内的日常运用极为广泛&#xff0c;涵盖了升旗仪式…

基于 SpringCloud 的在线交易平台乐优商城的设计与实现(四)

第 4 章 数据库设计 4.1 数据库设计原则 4.2.数据库概念结构设计 4.3 数据库表设计 4.4.本章小结 前面内容请移步 基于 SpringCloud 的在线交易平台乐优商城的设计与实现&#xff08;三&#xff09; 相关免费源码资源 乐优商城 第 4 章 数据库设计 4.1 数据库设计原…

怎样把音频压缩?3种简单的音频压缩方法分享

怎样把音频压缩&#xff1f;在数字化时代&#xff0c;音频文件占据了大量的存储空间&#xff0c;因此音频压缩成为了许多人的需求。通过音频压缩&#xff0c;我们不仅可以减小文件大小&#xff0c;方便存储和传输&#xff0c;还可以节省设备空间&#xff0c;提升处理效率。因此…

人工智能|推荐系统——推荐大模型最新进展

近年来,大语言模型的兴起为推荐系统的发展带来了新的机遇。这些模型以其强大的自然语言处理能力和丰富的知识表示,为理解和生成复杂的用户-物品交互提供了新的视角。本篇文章介绍了当前利用大型语言模型进行推荐系统研究的几个关键方向,包括嵌入空间的解释性、个性化推荐的知…

电脑黑屏问题的4种解决方法,两分钟轻松掌握

电脑黑屏是一种让人不安的问题&#xff0c;这个问题可能是由多种原因引起的。在这个数字化的时代&#xff0c;电脑已经成为我们工作和娱乐中不可或缺的一部分。当电脑突然陷入黑屏状态&#xff0c;用户通常会感到困扰和焦虑。本文将介绍一些常见的电脑黑屏问题解决方法&#xf…

微服务之并行与分布式计算

一、概述 1.1集中式系统vs分布式系统 集中式系统 集中式系统完全依赖于一台大型的中心计算机的处理能力&#xff0c;这台中心计算机称为主机&#xff08;Host 或 mainframe &#xff09;&#xff0c;与中心计算机相连的终端设备具有各不相同非常低的计算能力。实际上大多数终…

注意力机制、self attention、target attention、双层attention

关于注意力机制要解决2个问题&#xff0c;一是怎么做在哪个层面上做&#xff0c;二是注意力系数如何得到&#xff0c;由谁产出。注意力机制应用广泛的本质原因是求和的普遍存在&#xff0c;只要是有求和的地方加权和就有用武之地。DIN/DIEN把注意力机制用在用户行为序列建模是为…

校园综合服务平台

码功能强大&#xff0c;ui 精美&#xff0c; 功能包含但不限于校园跑腿&#xff0c;外卖&#xff0c;组局&#xff0c;圈子&#xff0c;商城&#xff0c;抽奖&#xff0c;投票&#xff0c;团购&#xff0c;二手市场&#xff0c;签到&#xff0c;积分商城&#xff0c;一元购等&a…

Linux驱动开发:深入理解I2C时序

目录标题 I2C简介I2C时序关键点Linux内核中的I2C时序处理I2C适配器I2C算法I2C核心 代码示例&#xff1a;I2C设备访问调试I2C时序问题 在Linux驱动开发中&#xff0c;理解和正确处理I2C时序对于确保I2C设备正常工作至关重要。本文将详细介绍I2C通信协议的时序特征&#xff0c;并…

企业的核心竞争力,是有效制作电子说明书

在这个信息化的时代&#xff0c;各种产品和服务层出不穷&#xff0c;数不胜数。要想在众多竞争对手中脱颖而出&#xff0c;除了产品质量之外&#xff0c;还有很多因素。比如营销手段、价格优势或者是品牌效应。但今天我要说的&#xff0c;是一个可能容易被人忽视的一个关键点—…

[嵌入式系统-53]:嵌入式系统集成开发环境大全

目录 一、嵌入式系统集成开发环境分类 二、由MCU芯片厂家提供的集成开发工具 三、由嵌入式操作提供的集成开发工具 四、由第三方工具厂家提供的集成开发工具 一、嵌入式系统集成开发环境分类 嵌入式系统集成开发工具和集成开发环境可以按照不同的分类方式进行划分&#xff…

SecretFlow学习指南(2)学习路径

目录 一、模块架构 二、模块详解 三、算法协议 四、学习路线 一、模块架构 良好的分层设计可以提高开发效率和可维护性&#xff0c;满足不同用户的需求。隐语从上到下一共分为六层。 ●产品层&#xff1a;通过白屏化产品提供隐语整体隐私计算能力的输出&#xff0c;让用户简…

Vue2和Vue3的生命周期对比

beforeCreate 、created 两个钩子被setup()钩子来替代。 所有生命周期前面加了on

LeetCode 2385.感染二叉树需要的总时间:两次搜索(深搜 + 广搜)

【LetMeFly】2385.感染二叉树需要的总时间&#xff1a;两次搜索&#xff08;深搜 广搜&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/amount-of-time-for-binary-tree-to-be-infected/ 给你一棵二叉树的根节点 root &#xff0c;二叉树中节点的值 互不…