美文网首页
java多态只能用在类似于 方法(父类) 吗?而 父类 = ne

java多态只能用在类似于 方法(父类) 吗?而 父类 = ne

作者: 十万嬉皮_c728 | 来源:发表于2022-06-08 16:11 被阅读0次

多态最大的作用就是为了传参提供便利,但我们不应该只看到这一层,还要往下再走走:为什么要用父类引用指向子类实例呢?

就好比你看到一把刀很锋利,可以切菜,你不应该疑惑“难道刀就是拿来切菜的吗”,而应该关注“为什么刀可以如此锋利”...

回到你的问题上来,我们更应该关心:为什么可以使用多态机制,以及为什么需要多态?

多态怎么实现的?

我并非计算机专业,所以对于这个问题,只给出一个大概的解释。多态从语法表面上看,就是子类对象可以赋值给父类引用,并且通过该引用可以动态地调用不同子类的方法。

多态按实际用法又可以分为:

  • 继承多态
  • 接口多态

所谓继承多态(吸烟有害健康,我不抽烟):

class Son extends Father {
    @Overrid
    public void smoke() {
        System.out.print("儿子抽烟");
    }
}
class Daughter extends Father {
    @Overrid
    public void smoke() {
        System.out.print("女儿抽烟");
    }
}

// 继承多态,因为Son、Daughter继承了Father
Father obj = new Son();
obj.smoke(); // 打印:儿子抽烟
obj = new Daughter();
obj.smoke(); // 打印:女儿抽烟

所谓接口多态:

class Son implements Swimmer {
    @Overrid
    public void swim() {
        System.out.print("儿子游泳");
    }
}
class Daughter implements Swimmer {
    @Overrid
    public void swim() {
        System.out.print("儿子游泳");
    }
}

// 接口多态,因为Son、Daughter实现了Swimmer
Swimmer obj = new Son();
obj.swim(); // 打印:儿子游泳
obj = new Daughter();
obj.swim(); // 打印:女儿游泳

实际开发接口多态更常用。

多态的实现,依赖于2个大方面:

  • 机制上的支持
  • 编码上的支持

机制支持

首先,编译器要允许这种赋值方式,不然把son赋值给swimmer就会像把 int a赋值给String b一样报错。

其次,运行时要支持并且能通过某种机制找到真正的子类方法。

编码支持

必须存在继承(实现)关系 + 子类必须重写(实现)父类的方法

我们一般所说的多态,其实都是指方法的多态

什么意思呢?以上面Swimmer的代码为例(假设整个工程只有这么几个类),当程序运行时,JVM中实际上并不存在一个对象叫Swimmer,自始至终只有Son和Daughter两个对象,而且Son和Daughter都实现了Swimmer,且重写了swim()方法。当JVM运行到:

image.png

JVM是怎么知道要打印“儿子游泳”的呢?换句话说,JVM怎么知道调用Son#swim()而不是Swimmer#swim()或者Daughter#swim()的呢?


image.png

这就涉及到所谓的“[虚方法]”和“虚方法表”了。JVM的知识点大概如下:


image.png

在类加载过程中,有loading、linking、initialization三个阶段,其中linking(链接)阶段又包括3个小阶段:

  • verify(验证)
  • prepare(准备)
  • resolve(解析)

其中在resolve阶段,JVM会针对类或接口、字段、类方法、接口方法等进行相应解析,其中方法信息会形成所谓的“虚方法表”。

image.png

也就是说,当出现多态方法调用时,底层会多一次“查表”的过程,也就是通过搜索虚方法表,确定本次实际应该调用的方法(实际指向对象+实例对应的类有无重写父类方法),如果子类Override了父类方法,那么就会执行子类方法。

多态与设计模式

很多初学编程的人,一定会记住两句话,即使他们并不懂得其中含义:

  • 面向对象的三大特性是:封装、继承、多态
  • 万物皆对象

但在我眼里,封装、继承这俩货和多态根本不是一个档次的(就好比李云迪和郎朗),多态才是面向对象的核心和根本,甚至没有多态就没有面向对象。举个例子,C语言没有封装吗?不也是可以抽取方法吗?也有结构体呢,看起来不像对象吗?再者,你问问自己,你使用继承是为了什么?不就是为了贪图父类的那一点点已经写好的方法,为了偷点懒吗?既然是为了少写一点代码,我抽取成方法不行吗?

所以,到底什么是面向对象呢?

这就回到了我上面说的,多态才是面向对象的核心(当然,面向对象本质是一种编程思想的转变)。当我们有了多态,才能写出更加抽象的代码,而抽象代表稳定

假设世界末日,外星人占领地球了,它们觉得必须杀鸡儆猴,我们因为真的打不过,只能任由宰割。此时我们签订契约:你们可以杀一个动物。于是我们送了一只实验室的小白鼠,因为小白鼠也是动物呀。动物这个词是抽象的,后面我们送啥都可以,只要不送人。

再举个编程的例子。假设在写好的一个类文件中,你写下这样一段代码:


image.png

如果后期接入拼多多,你就需要修改代码。但如果使用策略模式,就可以用增量的方式代替修改(开闭原则):

image.png image.png

具体可以参考:优化代码中大量的if/else,你有什么方案?

没错,这就是策略模式。而所谓的设计模式,其实有一本书的书名,恰恰点破了设计模式的本质:

image.png

是的,设计模式本质是围绕着“在面向对象的基础上,如何复用设计”这个原则展开的...所以本质又回到了面向对象。

为什么设计模式这么牛逼,能把很多看起来像“屎山一样”的代码优化得清晰、简洁?本质上就是多态!

所谓“屎山一样”的代码,大概率就是因为后期需求不断迭代,开发人员在未经思考的情况下肆意使用if else添加逻辑分支导致的!但分支是不会无缘无故消失的,只是借助设计模式把分支下推,最终交给了多态——JVM,你给我去查虚方法表。

换句话说就是:JVM,这坨屎你来吃。

最终,JVM带着虚方法表承受了一切,而我们的上层代码一扫阴霾,看起来干净而整洁,也就是所谓的clean code...

所以,最后再问一句:多态真的就是用来传参吗?

相关文章

  • java多态只能用在类似于 方法(父类) 吗?而 父类 = ne

    多态最大的作用就是为了传参提供便利,但我们不应该只看到这一层,还要往下再走走:为什么要用父类引用指向子类实例呢? ...

  • java基础问题

    在多态中,父类指向子类时候,不能调用父类没用,子类有的方法。 java中普通类可以继承普通类的。

  • 2.4 多态(面向对象)

    1、Java中的多态 对象的多种形态 引用多态父类的引用可以指向本类的对象父类的引用可以指向子类的对象 方法多态创...

  • 深入理解 Python 类和对象(1) - 鸭子类型和多态

    什么是鸭子类型? Java 中实现多态,需要继承父类,并覆盖父类中的方法。 Python 中实现多态,不需要继承任...

  • Java几个基本概念

    多态:通过父类指针调用子类方法 重载:一个类中方法参数名、个数、类型不同 重写:子类对父类方法的重写 Java泛型...

  • Java - Part 4

    一、多态 多态:是一个继承了父类的子类可以看作是它的父类。1、多态的条件 要有子父类关系 要有方法重写 要有父类引...

  • 多态只针对方法,而不是属性

    java中子类只能重写父类的方法 ,而不能重写属性 创建两个类,一个子类一个父类进行测试 父类 子类先建一个和父类...

  • Java学习笔记汇总

    待学习 ... Java多态的实现机制是什么 子类继承父类并覆写了父类的方法,当以父类声明并初始化一个子类型的时候...

  • 多态

    多态性(简化代码) - 多态的规则:里氏替换原则(子类替换父类方法:只是多态表现);多态的特性:父类保存了子类的对...

  • 26号c#总结

    26号 今天开始讲多态,在c和c++中都有涉及。继承是子类使用父类的方法,而多态则是父类使用子类的方法。重点内容是...

网友评论

      本文标题:java多态只能用在类似于 方法(父类) 吗?而 父类 = ne

      本文链接:https://www.haomeiwen.com/subject/eqvumrtx.html