「MoreThanJava」Day 6:面向对象进阶——多态

  • 「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」
  • 当然 不论新老朋友 我相信您都可以 从中获益。如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力!

Part 1. 多态概述

多态,简而言之就是 同一个行为 具有 多个不同表现形式 或形态的能力。在面向对象的程序设计中,多态的能力是通过数据抽象和继承之后得来的

「MoreThanJava」Day 6:面向对象进阶——多态_第1张图片

比如,有一杯水,我不知道它是温的、冰的还是烫的,但是我一摸我就知道了,我摸水杯的这个动作 (方法),对于不同温度的水 (运行时不同的对象类型),就会得到不同的结果,这就是多态。

代码演示:

// 基类定义
public class Water {
   
    public void showTem() {
    }
}
// 冰水
public class IceWater extends Water {
   

    @Override
    public void showTem() {
    System.out.println("我的温度是: 0度"); }
}
// 温水
public class WarmWater extends Water {
   
    @Override
    public void showTem() {
    System.out.println("我的温度是: 40度"); }
}
// 开水
public class HotWater extends Water {
   
    @Override
    public void showTem() {
    System.out.println("我的温度是: 100度"); }
}
// 测试类
public class TestWater {
   
    public static void main(String[] args) {
   
        Water w = new WarmWater();
        w.showTem();

        w = new IceWater();
        w.showTem();

        w = new HotWater();
        w.showTem();
    }
}

结果输出:

我的温度是: 40度
我的温度是: 0度
我的温度是: 100度

这里的方法 showTem() 就相当于你去摸水杯。我们定义的 Water 类型的引用变量 w 就相当于水杯,你在水杯里放了什么温度的水,那么我摸出来的感觉就是什么。就像代码中的那样,放置不同温度的水,得到的温度也就不同,但水杯是同一个。

里氏替换原则(LSP)

面向对象的设计原则有一条关于多态的原则,它的描述大概是这样子的:子类对象 (object of subtype/derived class) 能够 替换 程序 (program)父类对象 (object of base/parent class) 出现的 任何地方,并且 保证原来程序的逻辑行为 (behavior) 不变及正确性不被破坏

这么说可能有点抽象,简单说就是 子类和父类的行为应该保持一致

哪些代码明显违背了 LSP?

实际上,里式替换原则还有另外一个更加能落地、更有指导意义的描述,那就是 “Design By Contract”,中文翻译就是 “按照协议来设计”。定义中父类和子类之间的关系,也可以替换成接口和实现类之间的关系。

为了更好地理解这句话,我举几个违反里式替换原则的例子来解释一下。

1 - 子类违背父类声明要实现的功能

父类中提供的 sortOrdersByAmount() 订单排序函数,是按照金额从小到大来给订单排序的,而子类重写这个 sortOrdersByAmount() 订单排序函数之后,是按照创建日期来给订单排序的。那子类的设计就违背里式替换原则。

2 - 子类违背父类对输入、输出、异常的约定

在父类中,某个函数约定:运行出错的时候返回 null;获取数据为空的时候返回空集合(empty collection)。而子类重载函数之后,实现变了,运行出错返回异常(exception),获取不到数据返回 null。那子类的设计就违背里式替换原则。

3 - 子类违背父类注释中所罗列的任何特殊说明

父类中定义的 withdraw() 提现函数的注释是这么写的:“用户的提现金额不得超过账户余额……”,而子类重写 withdraw() 函数之后,针对 VIP 账号实现了透支提现的功能,也就是提现金额可以大于账户余额,那这个子类的设计也是不符合里式替换原则的。

当然,当前的大环境下,注释的可信度还是得斟酌斟酌… (不可尽信…)

Part 2. 向上转型 && 向下转型

再谈向上转型

在 上一篇文章 里面我们已经谈到 —— 对象既可以作为它本身的类型使用

你可能感兴趣的:(MoreThanJava,java,多态,后端)