我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【JAVA】多态

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【JAVA】多态

作者主页:paper jie_的博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JAVASE语法系列》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将javaSE基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《JAVA》《算法详解》《C语言》等

内容分享:本期将会对JAVA中的多态进行讲解

目录

多态的概念

多态的实现条件

重写

方法重写的规则

重写和重载的区别

重写的设计理念由来

向上转型和向下转型

向上转型

向下转型

多态的优缺点

使用多态的优点

多态的缺陷


简单的讲多态就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的形态。总的来说,同一件事,发生在不同的对象中,产生的结果是不同的。

在java中要实现多态需要满足几个条件:

1 必须要在继承的基础上发生向上转型

2 子类必须对父类中的方法重写

3 通过父类的引用调用重写的方法

多态的体现就在:代码运行时,当传递不同类的对象时,会调用对应类的重写方法。

class Animal {    String name;    int age;    public Animal(String name, int age){        this.name = name;        this.age = age;    }    public void eat(){        System.out.println(name + "吃饭");    }}class Cat extends Animal{    public Cat(String name, int age){        super(name, age);    } @            Override    public void eat(){        System.out.println(name+"吃鱼~~~");    }}class Dog extends Animal {    public Dog(String name, int age){        super(name, age);    } @            Override    public void eat(){        System.out.println(name+"吃骨头~~~");    }} ///分割线//class TestAnimal {// 编译器在编译代码时,并不知道要调用Dog 还是 Cat 中eat的方法// 等程序运行起来后,形参a引用的具体对象确定后,才知道调用那个方法// 注意:此处的形参类型必须时父类类型才可以    public static void eat(Animal a){        a.eat();    }    public static void main(String[] args) {        Cat cat = new Cat("元宝",2);        Dog dog = new Dog("小七", 1);        eat(cat);        eat(dog);    }}

在上述代码中, 分割线上方的代码是 类的实现者 编写的, 分割线下方的代码是 类的调用者 编写的. 
当类的调用者在编写 eat 这个方法的时候, 参数类型为 Animal (父类), 此时在该方法内部并不知道, 也不关注当前的a 引用指向的是哪个类型(哪个子类)的实例. 此时 a这个引用调用 eat方法可能会有多种不同的表现(和 a 引用的实例相关), 这种行为就称为 多态

重写:也叫做覆盖。重写是子类对父类非静态,非private修饰,非final修饰,非构造方法等的实现过程进行重写的编写,返回值和形参都不能变。重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是子类能够根据需要实现父类的方法。

方法重写的规则

子类在重写父类的方法时,必须与父类方法原形一致:返回值类型 方法名,参数列表

被重写的方法返回值类型可以不同,但是必须是具有父子关系的,叫做协变类型

访问权限不能比父类中被重写的方法的权限更低。

重写的方法,可以使用@Override 注解来指定,这个可以帮助我们进行合法性的效验

object类是所有类的父类,里面的方法都可以重写

重写和重载的区别

方法重载是一个类的多态性的表现

方法重写是子类和父类的一种多态性的表现

重写的设计理念由来

对于已经投入使用的类,就尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中的共性,并且添加或者改动新的内容。

例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们不应该在原来老的类上进行修改,因为原来的类,可能还在有用户使用,正确做法是:新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我们当今的需求了。 


向上转型

向上转型就是创建一个子类对象,当做父类对象来使用。

使用形式:父类类型 对象名 = new 子类对象类型();

栗子:

animal是父类类型,但是可以引用子类对象,它是从小范围转换为大范围。

Animal animal = new Dog("耀阳");

它有三种使用方法:
1直接赋值,2方法传参,3方法返回

class TestAnimal {    // 2. 方法传参:形参为父类型引用,可以接收任意子类的对象    public static void eatFood(Animal a){        a.eat();    } // 3. 作返回值:返回任意子类对象    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 cat = new Cat("元宝",2); // 1. 直接赋值:子类对象赋值给父类对象        Dog dog = new Dog("小七", 1);        eatFood(cat);        eatFood(dog);        Animal animal = buyAnimal("狗");        animal.eat();        animal = buyAnimal("猫");        animal.eat();    }}

向上转型就是可以让代码变的更加的简单灵活,但是它有一个缺陷就是不能调用到子类自己特有的方法。

向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。 

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,则可以安全转换。

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

使用多态的优点

可以降低代码的圈复杂度,避免大量的if else

什么叫 "圈复杂度" ?
圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂.
因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 "圈复杂度".
如果一个方法的圈复杂度太高, 就需要考虑重构.不同公司对于代码的圈复杂度的规范不一样. 一般不会超过 10 

栗子:

这里有一段代码:

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

现在我们需要打印的不是一个图形,而是一堆图形,不用多态的话,实现的代码:

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

如果使用多态,则不用使用这么过if else语句,代码更简洁

public static void drawShapes() {// 我们创建了一个 Shape 对象的数组.        Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),        new Rect(), new Flower()};        for (Shape shape : shapes) {        shape.draw();        }        }

可扩展能力强

如果要新增一种图形,使用多态的方式代码改动成本也比较低。

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

对于类的调用者来说(drawShapes方法), 只要创建一个新类的实例就可以了, 改动成本很低.
而对于不用多态的情况, 就要把 drawShapes 中的 if - else 进行一定的修改, 改动成本更高 

多态的缺陷

属性没有多态性

当父类和子类都用同名的属性的时候,通过父类的引用只能调用父类的成员属性

构造方法没有多态性

避免在构造方法中调用重写的方法

代码如下:

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 对象的同时, 会调用 B 的构造方法. 
B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0. 如果具备多态性,num的值应该是1.所以在构造函数内,尽量避免使用实例方法,除了final和private方法。
结论: "用尽量简单的方式使对象进入可工作状态", 尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题.
 


来源地址:https://blog.csdn.net/paperjie/article/details/132582212

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【JAVA】多态

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

2023-08-31

Java之多态

多态 多态的实现条件重写重写的定义重写的例子方法重写的条件 多态思想动态绑定与静态绑定 作者简介: zoro-1,目前大一,正在学习Java,数据结构等 作者主页:zoro-1的主页 欢迎大家点赞 👍
2023-08-16

java多态是什么

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: (推荐学习:java课程)多态性是对象多种表现形式的体现。现实中,比如我们按下 F1 键这个动作:如果当前在 Flash 界面下弹出的就是 AS
java多态是什么
2015-05-12

java 多态是什么

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:多态性是对象多种表现形式的体现。现实中,比如我们按下 F1 键这个动作:·如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;·如果当前在
java 多态是什么
2020-09-04

如何在 Java 中实现多态性?(java如何实现多态性)

在Java编程中,多态性是一个非常重要的概念,它允许对象根据其所属的类或实现的接口而表现出不同的行为。实现多态性有多种方式,以下是详细的介绍。一、方法重载(Overloading)方法重载是在同一个类中定义多个具有相同名称但
如何在 Java 中实现多态性?(java如何实现多态性)
Java2024-12-15

java 多态实例代码

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作。多态性是对象多种表现形式的体现,比如:在现实中,我们按下F1键这个动作:如果当前在Flash界面下弹出的就是AS 3的帮助文档如果当前在Wo
2023-05-30

java如何实现多态

Java多态概述:(推荐:java视频教程)多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。Java 对于方法调用动态绑定的实现主要依赖于方法表,但通过类引用调用(invokevitual)和接口引用
java如何实现多态
2020-07-13

java多态怎么理解

这篇文章主要介绍java多态怎么理解,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在java中,多态是同一个行为具有多个不同表现形式或形态的能力;多态就是同一个接口,使用不同的实例而执行不同操作。多态的优点:1、消除
2023-06-14

如何理解 Java Construct 的继承和多态?(Java Construct的继承和多态)

在Java编程中,JavaConstruct的继承和多态是两个非常重要的概念,它们对于构建复杂的面向对象程序起着关键作用。一、继承(Inheritance)继承是面向对象编程的三大特性之一,它允许
如何理解 Java Construct 的继承和多态?(Java Construct的继承和多态)
Java2024-12-22

Java多态性怎么理解

本篇内容主要讲解“Java多态性怎么理解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多态性怎么理解”吧!面向对象编程有三个特征,即封装、继承和多态。封装隐藏了类的内部实现机制,从而可以
2023-06-17

Java中的继承与多态

在这篇文章中,我们探讨了Java中的继承和多态,这是面向对象编程的两个基本概念。通过使用extends关键字、方法重写和接口,我们可以创建更多可重用的、可扩展的和模块化的代码。理解这些概念不仅可以帮助你成为一个更好的Java开发者,还可以提

java面向对象之多态

多态的简单理解:student类继承了Person类,则student类的对象既是student又是person类多态性具有两种展现的形式:1.方法的多态性:(1)方法的重载:同一个方法可以根据传入的参数的类型或者个数的不同实现不同的功能(2)方法的覆写:同一
java面向对象之多态
2019-03-28

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录