面向对象特征三:多态性

一千个读者眼中有一千个哈姆雷特。

 多态的形式和体现

对象的多态性

多态性,是面向对象中最重要的概念,在Java中的体现:对象的多态性:父类的引用指向子类的对象

格式:(父类类型:指子类继承的父类类型,或者实现的接口类型)

父类类型 变量名 = 子类对象;

举例:

Person p = new Student();

Object o = new Person();//Object类型的变量o,指向Person类型的对象

o = new Student(); //Object类型的变量o,指向Student类型的对象

 对象的多态:在Java中,子类的对象可以替代父类的对象使用。所以,一个引用类型变量可能指向(引用)多种不同类型的对

 多态的理解

Java引用变量有两个类型:编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边。

  • 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)

  • 多态情况下,“看左边”:看的是父类的引用(父类中不具备子类特有的方法) “看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)

多态的使用前提:① 类的继承关系 ② 方法的重写

 举例

package com.atguigu.polymorphism.grammar;

public class Pet {
    private String nickname; //昵称

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public void eat(){
        System.out.println(nickname + "吃东西");
    }
}

package com.atguigu.polymorphism.grammar;

public class Cat extends Pet {
    //子类重写父类的方法
    @Override
    public void eat() {
        System.out.println("猫咪" + getNickname() + "吃鱼仔");
    }

    //子类扩展的方法
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}

package com.atguigu.polymorphism.grammar;

public class Dog extends Pet {
    //子类重写父类的方法
    @Override
    public void eat() {
        System.out.println("狗子" + getNickname() + "啃骨头");
    }

    //子类扩展的方法
    public void watchHouse() {
        System.out.println("看家");
    }
}

1、方法内局部变量的赋值体现多态

package com.atguigu.polymorphism.grammar;

public class TestPet {
    public static void main(String[] args) {
        //多态引用
        Pet pet = new Dog();
        pet.setNickname("小白");

        //多态的表现形式
        /*
        编译时看父类:只能调用父类声明的方法,不能调用子类扩展的方法;
        运行时,看“子类”,如果子类重写了方法,一定是执行子类重写的方法体;
         */
        pet.eat();//运行时执行子类Dog重写的方法
//      pet.watchHouse();//不能调用Dog子类扩展的方法

        pet = new Cat();
        pet.setNickname("雪球");
        pet.eat();//运行时执行子类Cat重写的方法
    }
}

2、方法的形参声明体现多态

package com.atguigu.polymorphism.grammar;

public class Person{
    private Pet pet;
    public void adopt(Pet pet) {//形参是父类类型,实参是子类对象
        this.pet = pet;
    }
    public void feed(){
        pet.eat();//pet实际引用的对象类型不同,执行的eat方法也不同
    }
}

package com.atguigu.polymorphism.grammar;

public class TestPerson {
    public static void main(String[] args) {
        Person person = new Person();

        Dog dog = new Dog();
        dog.setNickname("小白");
        person.adopt(dog);//实参是dog子类对象,形参是父类Pet类型
        person.feed();

        Cat cat = new Cat();
        cat.setNickname("雪球");
        person.adopt(cat);//实参是cat子类对象,形参是父类Pet类型
        person.feed();
    }
}

3、方法返回值类型体现多态

package com.atguigu.polymorphism.grammar;

public class PetShop {
    //返回值类型是父类类型,实际返回的是子类对象
    public Pet sale(String type){
        switch (type){
            case "Dog":
                return new Dog();
            case "Cat":
                return new Cat();
        }
        return null;
    }
}

package com.atguigu.polymorphism.grammar;

public class TestPetShop {
    public static void main(String[] args) {
        PetShop shop = new PetShop();

        Pet dog = shop.sale("Dog");
        dog.setNickname("小白");
        dog.eat();

        Pet cat = shop.sale("Cat");
        cat.setNickname("雪球");
        cat.eat();
    }
}

为什么需要多态性(polymorphism)?

开发中,有时我们在设计一个数组、或一个成员变量、或一个方法的形参、返回值类型时,无法确定它具体的类型,只能确定它是某个系列的类型。

案例:

(1)声明一个Dog类,包含public void eat()方法,输出“狗啃骨头”

(2)声明一个Cat类,包含public void eat()方法,输出“猫吃鱼仔”

(3)声明一个Person类,功能如下:

  • 包含宠物属性

  • 包含领养宠物方法 public void adopt(宠物类型Pet)

  • 包含喂宠物吃东西的方法 public void feed(),实现为调用宠物对象.eat()方法

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

public class Cat {
    public void eat(){
        System.out.println("猫吃鱼仔");
    }

public class Person {
    private Dog dog;

    //adopt:领养
    public void adopt(Dog dog){
        this.dog = dog;
    }

    //feed:喂食
    public void feed(){
        if(dog != null){
            dog.eat();
        }
    }
    /*
    问题:
    1、从养狗切换到养猫怎么办?   
        修改代码把Dog修改为养猫?
    2、或者有的人养狗,有的人养猫怎么办?  
    3、要是还有更多其他宠物类型怎么办?
    如果Java不支持多态,那么上面的问题将会非常麻烦,代码维护起来很难,扩展性很差。
    */
}

 多态的好处和弊端

好处:变量引用的子类对象不同,执行的方法就不同,实现动态绑定。代码编写更灵活、功能更强大,可维护性和扩展性更好了。

弊端:一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。

Student m = new Student();
m.school = "pku";   //合法,Student类有school成员变量
Person e = new Student(); 
e.school = "pku";   //非法,Person类没有school成员变量
​
// 属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

开发中:

使用父类做方法的形参,是多态使用最多的场合。即使增加了新的子类,方法也无需改变,提高了扩展性,符合开闭原则。

【开闭原则OCP】

  • 对扩展开放,对修改关闭

  • 通俗解释:软件系统中的各种组件,如模块(Modules)、类(Classes)以及功能(Functions)等,应该在不修改现有代码的基础上,引入新功能

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

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

相关文章

怎么对电脑屏幕进行远程控制

远程控制是指管理人员在异地通过计算机网络异地拨号或双方都接入Internet等手段,连通需被控制的计算机,将被控计算机的桌面环境显示到自己的计算机上,通过本地计算机对远方计算机进行配置、软件安装程序、修改等工作。 远程控制并不仅仅局限…

kettle使用MD5加密增量获取接口数据

kettle使用MD5加密增量获取接口数据 场景介绍: 使用JavaScript组件进行MD5加密得到Http header,调用API接口增量获取接口数据,使用json input组件解析数据入库 案例适用范围: MD5加密可参考、增量过程可参考、调用API接口获取…

docker容器之etcd安装

一、etcd介绍 1、etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。 2、etcd特点 简单的接口,通过标准的HTTP API进行调用,也可以使用官方提供的 etcdctl 操作存储的数据。…

Adaboost集成学习 | Matlab实现基于LSTM-Adaboost长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Adaboost集成学习 | Matlab实现基于LSTM-Adaboost长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测) 模型设计 股票价格预测是一个具有挑战性的时间序列预测问题,可以使用深度学习模型如…

Linux和Windows安装PHP依赖管理工具Composer

Composer 是 PHP 的一个依赖管理工具。它允许申明项目所依赖的代码库,会在项目中安装它们。 Composer 不是一个包管理器。是的,它涉及 "packages" 和 "libraries",但它在每个项目的基础上进行管理,在你项目的…

【Linux】Linux工具学习之gdb

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一、生成可调式文件1.1 release与debug 二、调试打开与关闭2.1 启动调试2.2 l 查…

element-ui tag 组件源码分享

今日简单分享一下 tag 组件的源码实现,主要从以下三个方面来分享: 1、tag 组件页面结构 2、tag 组件属性 3、tag 组件方法 一、tag 组件页面结构 vue2 中使用 jsx 语法小结: 1.1 需要安装 babel-plugin-transform-vue-jsx 和 vue/babel-…

标准库不带操作系统移植FreeModbus到STM32

添加FreeModbus代码 首先准备一个空白的标准库项目。 下载FreeModbus源码。 将源码中的modbus文件夹复制到项目路径下,并把demo->BARE->port文件夹的内容也添加进来。 新建一个文件port.c备用。然后打开项目,将上述文件添加至项目,…

Kubernetes(k8s):网络插件之Calico安装与详解

Kubernetes(k8s):网络插件之Calico安装与详解 1、什么是Calico?2、安装和配置Calico(控制节点-master执行)3、配置网络策略4、 Calico 的 yaml 文件部分详解1、ConfigMap配置2、DaemonSet 配置 5、calico-k…

【自我提升】一、Hyperledger Fabric 概念梳理

写在前面:最近因为业务需要,开始学习Hyperledger Fabric了,做java全栈工程师可真难搞。现在算是啥类型的都在涉及了,现在这个技术啥都不懂,就先开个学习专栏,记录记录。顺带也给各位道友参考参考。 目录 …

选择决定财富,将有更多普通人选择MVP

伴随着又一次市场规律的到来,模因币开始来到属于自己的增长时期。 市场中的模因币都进入了暴涨状态,然而需要提醒的是。由于模因币基于MEME文化的加密货币。作为加密市场的新趋势,模因币与比特币等传统加密货币不同,通常没有实际…

hyper-v安装 windows10虚拟机后,登录一直是锁屏界面,无法开启增强会话

按键盘等,一直在锁屏界面,进不去,需要点击 上述图片按钮,切到 “基本会话”, 这样可以登录了; 切换到 ‘基本会话’ ,登陆后, 打开 设置--登录选项--要求 Microsoft 账户使用Windo…