多态详解

多态综述

class Shape {
    public void draw() {
    }
}
class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("○");
    }
}
class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("□");
    }
}
class Flower extends Shape {
    @Override
    public void draw() {
        System.out.println("♣");
    }
}

public class dd {
    public static void main(String[] args) {
        Shape shape1 = new Flower();
        Shape shape2 = new Cycle();
        Shape shape3 = new Rect();
        drawShape(shape1);
        drawShape(shape2);
        drawShape(shape3);
    }
    // 打印单个图形
    public static void drawShape(Shape shape) {
        shape.draw();
    }
}

输出结果
在这里插入图片描述

当类的调用者在编写 drawShape 这个方法的时候, 参数类型
Shape(父类), 此时在该方法内部并不知道, 也不关注当前的
shape 引用指向的是哪个类型(哪个子类)的实例. 此时shape
 这个引用调用 draw 方法可能会有多种不同的 表现(和 shape
  对应的实例相关), 这种行为就称为 多态.

多态顾名思义, 就是 "一个引用, 能表现出多种不同形态"
如上面的例子,只是调用了drawShape方法,却打印出
了不同的形状,这就是多态。

再举个具体的例子. 小明家里养了两只鹦鹉(圆圆和扁扁)和
一个小孩(蛋蛋). 小明媳妇管他们都叫 "儿子". 这时候小明
对我媳妇说, "你去喂喂你儿子去". 那么如果这里的 "儿子"
 指的是鹦鹉, 小明媳妇就要喂鸟粮; 如果这里的 "儿子" 指
 的是蛋蛋, 小明媳妇就要喂馒头.那么如何确定这里的 
 "儿子" 具体指的是啥? 那就是根据我和媳妇对话之间的
  "上下文".代码中的多态也是如此. 一个引用到底是指向
  父类对象, 还是某个子类对象(可能有多个), 也是要根据
  上下文的代码来确定.

多态的分类

 对于面向对象而言,多态分为编译时多态和运行时多态。
 其中编辑时多态是静态的,主要是指方法的重载,它是
 根据参数列表的不同来区分不同的函数,通过编辑之后
 会变成两个不同的函数,在运行时谈不上多态。而运行
 时多态是动态的,它是通过动态绑定来实现的,也就是
 我们所说的多态性。

多态实现条件

 Java实现多态有三个必要条件:
1、继承
2、方法重写
3、向上转型。
 对于Java而言,它多态的实现机制遵循一个原则:当父类
 引用引用子类对象时,被引用对象的类型决定了调用谁的
 成员方法,而不是父类引用。但是这个被调用的方法必须
 是在超类中定义过的,也就是被子类重写的方法。

多态的实现形式

  在Java中有两种形式可以实现多态:继承和接口。
1、基于继承实现的多态
基于继承的实现机制主要表现在父类和继承该父类的一个或
多个子类对某些方法的重写,多个子类对同一方法的重写可
以表现出不同的行为。

基于继承实现的多态可以总结如下:
对于引用子类的父类类型,在处理该引用时,它适用于继承
该父类的所有子类,子类对象的不同,对方法的实现也就不
同,执行相同动作产生的行为也就不同。

如果父类是抽象类,那么子类必须要实现父类中所有的抽象
方法,这样该父类所有的子类一定存在统一的对外接口,但
其内部的具体实现可以各异。这样我们就可以使用顶层类提
供的统一接口来处理该层次的方法。

2、基于接口实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的,那
么接口就是通过实现接口并覆盖接口中同一方法的几不同的类
体现的。

在接口的多态中,指向接口的引用必须是指定这实现了该接口
的一个类的实例程序,在运行时,根据对象引用的实际类型来
执行对应的方法。

 继承都是单继承,只能为一组相关的类提供一致的服务接口。
 但是接口可以是多继承多实现,它能够利用一组相关或者不
 相关的接口进行组合与扩充,能够对外提供一致的服务接口。
 所以它相对于继承来说有更好的灵活性。

多态的好处

1) 类调用者对类的使用成本进一步降低.
封装是让类的调用者不需要知道类的实现细节.多态能让类的
调用者连这个类的类型是什么都不必知道, 只需要知道这个对
象具有某个方法即可.。因此, 多态可以理解成是封装的更进
一步, 让类调用者对类的使用成本进一步降低.

2) 能够降低代码的 "圈复杂度", 避免使用大量的 if - else
例如我们现在需要打印的不是一个形状了, 而是多个形
状. 如果不基于多态, 就要通过if -else不断地判断究竟
是要打印哪个图形。

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

3) 可扩展能力更强.
如果要新增一种新的形状, 使用多态的方式代码改动成本也
比较低.对于类的调用者来说(drawShapes方法), 只要创建
一个新类的实例就可以了, 改动成本很低.而对于不用多态
的情况, 就要把 drawShapes 中的 if - else 进行一定的修
改, 改动成本更高.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值