【JavaSE】关于多态那些事儿

news2024/11/19 3:40:49

目录

1. 多态

1.1 多态的概念

1.2 多态实现条件

1.3 向上转型

1.3.1  直接赋值

1.3.2 方法传参

1.3.3 方法返回

1.3.4 向上转型的优缺点

1.4 重写

1.4.1 重写的条件

1.4.2 重写注意事项

1.4.3 重载与重写的区别

1.5 通过父类的引用,调用这个父类和子类重写的方法

2. 多态的应用——画图形


1. 多态

1.1 多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。比如吃饭这件事,猫吃猫粮,狗吃狗粮,人吃饭。再比如与人沟通这件事,中国人说中文,美国人说英语、法国人说法语。

在上一篇文章中(【JavaSE】继承那些事儿) ,提到过一句话,继承是对共性的抽取,实现代码的复用。就是对子类来说,它既有父类中的属性和方法,又有自己不同于其他子类,独特的属性和方法。而对父类里的方法来说,虽是共性,但依旧可以因为子类的不同,出现五花八门的形式,这就是多态。可以说,多态是针对父类而言的。

1.2 多态实现条件

在java中要实现多态,必须要满足如下几个条件,缺一不可:

1. 必须在继承体系下

2. 子类必须要对父类中方法进行重写

3. 通过父类的引用调用重写的方法多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

1.3 向上转型

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。

语法格式:父类类型 对象名 = new 子类类型()

Animal animal = new Cat("元宝",2);

写这么一个动物类,及其两个子类Cat类和Bird类:

class Animal{
    protected String name;
    protected int age;
    protected double weight;

    public Animal() {
    }

    public Animal(String name, int age, double weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public void eat(){
        System.out.println(this.name+ " 在吃饭!");
    }

    public void sleep(){
        System.out.println(this.name+" 在睡觉!");
    }
}

class Cat extends Animal{
    public Cat() {
    }

    public Cat(String name, int age, double weight) {
        super(name, age, weight);
    }

    public void mew(){
        System.out.println(this.name+" 喵~喵~喵~");
    }
}

class Bird extends Animal{
    public Bird() {
    }

    public Bird(String name, int age, double weight) {
        super(name, age, weight);
    }

    public void fly(){
        System.out.println(this.name+" 正在天空翱翔!");
    }
}

那么该如何向上转型呢?有下面几种方式:

1.3.1  直接赋值

public class Text {
    public static void main(String[] args) {
        Animal animal1 = new Cat("Hello Kitty",1,7);
        animal1.sleep();
        animal1.eat();
        //animal1.mew(); 编译报错

        Animal animal2 = new Bird("AngryBird",3,5.5);
        animal2.eat();
        animal2.sleep();
    }
}

按理说,等号两边的数据类型应该相同,否则会报错。但上述代码能运行的一个主要原因就是,两者有一个继承的关系。

1.3.2 方法传参

public class Text {
    public static void function(Animal animal){
        animal.eat();
        animal.sleep();
    }
    public static void main(String[] args) {
        Animal animal1 = new Cat("Hello Kitty",1,7);
        function(animal1);

        Animal animal2 = new Bird("AngryBird",3,5.5);
        function(animal2);
    }
}

1.3.3 方法返回

public class Text {
    public static Animal function(String type){
        if("鸟".equals(type)){
            return new Bird("AngryBird",3,5.5);
        }else{
            return new Cat("Hello Kitty",1,7);
        }

    }
    public static void main(String[] args) {
        Animal animal1 = function("猫");
        animal1.sleep();
        animal1.eat();
        Animal animal2 = function("鸟");
        animal2.sleep();
        animal2.eat();
    }
}

向上转型导致的一个结果,就是父类的引用,是不能访问子类中父类所没有的属性及方法的,即子类特有的属性和方法。

1.3.4 向上转型的优缺点

向上转型的优点:让代码实现更简单灵活。

向上转型的缺陷:不能调用到子类特有的方法。

1.4 重写

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法的实现过程进行重新编写。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

1.4.1 重写的条件

1. 方法名相同

2. 形参数目、顺序相同

3. 返回值相同

再次利用上面动物类及两个子类的例子:

class Animal{

    ......
    ......

    public void eat(){
        System.out.println(this.name+ " 在吃饭!");
    }

    public void sleep(){
        System.out.println(this.name+" 在睡觉!");
    }
}


class Cat extends Animal{

    ......
    ......

    public void eat(){
        System.out.println(this.name + " 在吃主人给的小零食~");
    }

    public void sleep(){
        System.out.println(this.name+" 正在狗窝里呼呼大睡");
    }
}

class Bird extends Animal{
    
    ......
    ......

    public void eat(){
        System.out.println(this.name+ " 叼着一只肥美的大青虫");
    }

    public void sleep(){
        System.out.println(this.name+" 站在枝桠上睡大觉,沐浴着月光,微风吹拂着");
    }
}

 重写之后,我们的IDEA会出现以下的图标:

 我们可以利用注解 @Override 来检查重写的语法规则是否正确:

    @Override
    public void eat(int a){
        System.out.println(this.name + " 在吃主人给的小零食~");
    }

 像这样的代码,@Override 那行的代码就会有警告。

同样也可以让编译器自动生成:右击Generate -> Override Methods -> Animal 类中 -> eat()

1.4.2 重写注意事项

1. private 修饰的方法不能被重写

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

3. 子类重写方法的访问权限要大于等于父类被重写的方法

4. 被 final 修饰的方法不能被重写,此时这个方法被称作密封方法

5. 构造方法不能被重写

1.4.3 重载与重写的区别

区别重写(override)重载(overload)
参数列表必须相同必须不同
返回类型必须相同【除非可以构成父子类关系】可以不同
访问限定符有一定的要求,见上文可以不同

即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

【重写的设计原则】

对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容, 并且添加或者改动新的内容。例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们不应该在原来老的类上进行修改,因为原来的类,可能还在有用户使用,正确做法是:新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我 们当今的需求了。

1.5 通过父类的引用,调用这个父类和子类重写的方法

接下来,让我们来看看,向上转型 -> 重写 之后,再一次使用父类引用调用重写的方法会怎么样:

public class Text {
    public static void main(String[] args) {
        Animal animal1 = new Cat("Hello Kitty",1,7);
        animal1.sleep();
        animal1.eat();

        Animal animal2 = new Bird("AngryBird",3,5.5);
        animal2.sleep();
        animal2.eat();
    }
}

 输出:

         Hello Kitty 正在狗窝里呼呼大睡
         Hello Kitty 在吃主人给的小零食~
         AngryBird 站在枝桠上睡大觉,沐浴着月光,微风吹拂着
         AngryBird 叼着一只肥美的大青虫

向上转型 -> 重写 -> 父类引用调用子类重写父类的方法,这三个过程合在一起,会发生 动态绑定:编译的时候,会调用父类的方法,但是在运行的时候,帮我们调用了子类重写的方法。

查看编译完成之后的字节码文件,可以佐证我的说法:

 只是动态绑定会帮我们调用子类的重写方法。

动态绑定是多态的基础!

动态绑定与静态绑定的区别:

静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。

动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

2. 多态的应用——画图形

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

class Rectangle extends Shape{
    void draw(){
        System.out.println(" ⬜");
    }
}

class Circle extends Shape{
    void draw(){
        System.out.println(" ⚪");
    }
}

class Triangle extends Shape{
    void draw(){
        System.out.println(" 🔺");
    }
}

class Flowers extends Shape{
    void draw(){
        System.out.println("~❀~");
    }
}

public class Text {


    public static void main(String[] args) {
        Rectangle rect = new Rectangle();
        Circle cir = new Circle();
        Triangle tri = new Triangle();
        Flowers flower = new Flowers();

        Shape[] shapes = {flower,rect,flower,cir,flower,tri,flower,tri,flower,cir,flower,rect,flower};

        for(Shape shape : shapes){
           shape.draw();
        }
    }

输出 

       ~❀~
        ⬜
       ~❀~
        ⚪
       ~❀~
        🔺
       ~❀~
        🔺
       ~❀~
        ⚪
       ~❀~
        ⬜
       ~❀~

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

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

相关文章

CSS篇十六——盒子模型之边框

目录一、CSS盒子模型1.1 盒子模型组成1.2 边框(border)1.2.1 语法格式1.2.2 边框样式 border-style1.2.3 代码示例1.3 表格的细线边框1.3.1 语法格式、代码示例及结果一、CSS盒子模型 网页布局过程: 1.先准备好相关的网页元素,网…

My sql的深度剖析

一.数据库的创建、删除、使用 数据库的创建:create database 数据库名 数据库的删除:drop database 数据库名; 数据库的使用:use数据名; 所有数据库的查看:show databases; 建立数据时如何指定字符集…

在Java中计算Levenshtein莱文斯坦(相似度)编辑距离

在本教程中,我们将研究 Levenshtein 距离算法,该算法也称为编辑距离算法,用于比较单词的相似性。 什么是列文施泰因距离 Levenshtein距离算法由俄罗斯科学家Vladimir Levenshtein创建。 Levenshtein 距离算法通过计算将一个字符串转换为另…

基于单片机的贪吃蛇设计

1 绪论 1.1 设计目的 在21世纪的今天,人们的生活开始变得更加丰富多彩。在繁忙的工作之余,娱乐成为人们生活不可或缺的一份子,而游戏作为近年来逐渐兴起的一种娱乐方式,已经越来越受到人们的青睐。在工作学习之余&#…

dreamweaver网页设计作业制作 学生NBA篮球网页 WEB静态网页作业模板 大学生校园篮球网页代码 dw个人网页作业成品

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

第五章:双指针与离散化的映射

第五章:双指针、离散化、二进制运算与区间合并一、双指针1、什么是双指针?2、双指针的模板3、双指针例题(1)思路:(2)解答:C版:C版:二、离散化1、什么是离散化…

java面试强基(3)

重载和重写的区别? 重载 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。 重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。 重写 重写发生在运行期,…

go语言基本环境搭建

下载地址 Go官网下载地址:https://studygolang.com/dl 一、下载对应电脑得安装包 二、下载完成点击安装下一步(选择目录尽量简单) 三、是否安装成功 四、环境变量 GOROOT和GOPATH都是环境变量,其中GOROOT是我们安装go开发包的路…

【计算机毕业设计】Springboot医疗管理系统源码

一、系统截图(需要演示视频可以私聊) 摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 医疗服务系统,主要的模块包括查看管理员;首页、个人中心…

tomcat官网下载配置全部详细步骤(包含各种报错解决办法)

前言: 名字由来:翻译是野猫,tomcat的作者初衷是希望这个软件可以自力更生,自给自足。不依赖其他插件,独立达到提供web服务的效果 1.tocat和java的关系? tomcat是用Java语言编写的,需要运行在…

大三,请问现在自学Java还来得及吗?

前言 如果还在为入门Java晚而发愁时间够不够,首先你是准备自学,那么我们可以看看现在网络上一些比较热门的Java全体系的学习需要化多长时间,先拿B站上做的比较好的黑马教程和尚硅谷举例: 2022黑马程序员Java学习路线图​www.bili…

耗时半月,终于把牛客网软件测试面试八股文,整理成了文档资料.....

一、面试基础题 简述测试流程: 1、阅读相关技术文档(如产品PRD、UI设计、产品流程图等)。 2、参加需求评审会议。 3、根据最终确定的需求文档编写测试计划。 4、编写测试用例(等价类划分法、边界值分析法等)。 5、用例评审(…

飞象星球落地重庆云阳86所学校,县乡4万学生迎来素质课堂

猜生字笔画顺序、学习硬笔书法;跟随老师认识情绪、写下心里话……自从重庆云阳县86所中小学引入飞象星球双师素质课堂,4万多名县城和乡村孩子的课后素质课堂一下子变得丰富多彩起来。 图:洞鹿小学双河村校上双师素质书法课 云阳县地处三峡库…

代码随想录算法训练营第三十六天| LeetCode435. 无重叠区间、LeetCode763. 划分字母区间、LeetCode56. 合并区间

一、LeetCode435. 无重叠区间 1:题目描述(435. 无重叠区间) 给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 2:解题思路 class …

MySQL面试问题汇总(2022)

一、MySQL架构 锁 什么是锁? 当多个连接并发地存取MySQL数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。 加锁是实现数据库并发控制的一个非常重要的…

BFV同态加密方案初步学习

BFV是把Bra12的LWE版本推到了RLWE版本,Bra12也可以叫做BFV。 经典的RLWE的公钥加密算法回顾 对比以前的Regev的LWE公钥加密方案,其实几乎只是把明文空间换了,也就是在最大比特编码的时候把2换成t,即,Δ⌊q/t⌋\Delta…

web网页设计期末课程大作业——香格里拉旅游网页设计 5页 HTML+CSS+JavaScript

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法,如盒子的嵌套、浮动、margin、border、background等属性的使用,外部大盒子设定居中,内部左中右布局,下方横向浮动排列,大学学习的前端知识点和布局方式都有…

一起来看看AMD最新显卡驱动22.11.1!

AMD最新推出了显卡驱动22.11.1,可以支持新上线的使命召唤:战区2,并且还修复了一系列的问题,AMD忠实用户们期待了嘛~ 更新内容 支持 使命召唤:战区 2.0 漫威蜘蛛侠:迈尔斯莫拉莱斯™ 固定问题 Radeon™ RX 6…

【mycat】mycat水平分表

mycat完成水平拆分 简介 相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的…

【Try Hack Me】内网专项---Wreath

THM 学习笔记 【Try Hack Me】内网专项—Wreath 🔥系列专栏:Try Hack Me 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📆首发时间:🌴2022年11月17日🌴 🍭作…