在了解完 抽象类 之后,我们对多态进行学习
什么是多态
我们可以将它理解为品牌,如冰箱的牌子:美的、华凌、小天鹅,打印机的牌子:黑白打印机、彩色打印机等等——它们具有同一种行为,但由于条件不同,或者说所属类不同,导致同一行为下产生的结果会有差别
在 java 中多态的概念如下:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说,就是用父类(也称基类)的引用指向子类的对象
为什么需要多态
先看如下代码
public class OldMan {
// 喂养狗狗
public void feedAnimal(Dog dog){
dog.eat();
}
// 喂养猫咪
public void feedAnimal(Cat cat){
cat.eat();
}
// 喂养小兔子
public void feedAnimal(Bird bird){
bird.eat();
}
}
对于老人这个类而言,利用重写,我们只需要调用 feedAnimal() 方法即可对不同对象执行同一操作,是不是看起来很方便? 但是如果此时老人新养了一只兔子呢?新建了一个类之后是不是又需要对老人这个类进行追加呢?这增加了写代码的复杂度和不稳定性
例如王者荣耀,原版本是较为稳定的程序框架,但若不使用多态,除了添加一个新英雄的类,还会对主题框架进行增改,这就使游戏整体的稳定性下降了。多态的诞生完美地解决了这个问题
如何使用多态
废话不多说,一学就会,上代码
public class OldMan {
// public void feedAnimal(Dog dog){
// dog.eat();
// }
// public void feedAnimal(Cat cat){
// cat.eat();
// }
// public void feedAnimal(Bird bird){
// bird.eat();
// }
public void feedAnimal(Animal animal){
animal.eat();
}
}
这样,多态就实现了(用父类的引用指向子类的对象)
多态内存图
我们来看下面这段代码
public static void main(String[] args) {
OldMan oldMan = new OldMan();
Dog dog = new Dog();
dog.setName("小狗");
oldMan.feedAnimal(dog);
}
我们画出内存分析图
从内存分析图上不难看出,多态的实现是通过调用方法为运行时动态生成的 Dog 对象指向的Dog:eat() 方法实现
多态两要素
- 父类引用指向子类,需要有继承关系
- 子类需要重写父类的方法
里氏代换原则
对于 里氏代换原则,简单来讲,要实现多态,需要使整体程序减少对子类的依赖,增加对抽象类的依赖。可以概述为以下:
1、子类可以实现父类的抽象方法,但不能覆盖父类的普通方法(非抽象方法)
2、子类可以添加自己特有的方法,但在实现多态时,一般使用重写的抽象方法
3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系