Java多态特征与3种实现方式详解

Java多态特征与3种实现方式详解-mikechen

Java面向对象的三大特性:封装、继承、多态,在这三个特性中,如果没有封装和继承,也不会有多态,那什么是多态?多态有哪些实现方式呢?本文会一一详解。

什么是多态

多态是同一个行为具有多个不同表现形式或形态的能力。

举个栗子,一只鸡可以做成白切鸡、豉油鸡、吊烧鸡、茶油鸡、盐焗鸡、葱油鸡、手撕鸡、清蒸鸡、叫花鸡、啤酒鸡、口水鸡、香菇滑鸡、盐水鸡、啫啫滑鸡、鸡公煲等等。

多态实现的必要条件用上面的“鸡的十八种吃法“来举个栗子。首先,我们先给出一只鸡:

class Chicken{
    public void live(){
        System.out.println("这是一只鸡");
    }
}

1. 子类必须继承父类

对于子类必须继承父类,小编个人认为,是因为按照面向对象的五大基本原则所说的中的依赖倒置原则:抽象不依赖于具体,具体依赖于抽象

既然要实现多态,那么必定有一个作为”抽象”类来定义“行为”,以及若干个作为”具体”类来呈现不同的行为形式或形态。

所以我们给出的一个具体类——白切鸡类:

class BaiqieChicken extends Chicken{ }

但仅是定义一个白切鸡类是不够的,因为在此我们只能做到复用父类的属性和行为,而没有呈现出行为上的不同的形式或形态

2. 必须有重写

重写,简单地理解就是重新定义的父类方法,使得父类和子类对同一行为的表现形式各不相同。我们用白切鸡类来举个栗子。

class BaiqieChicken extends Chicken{
    public void live(){
        System.out.println("这是一只会被做成白切鸡的鸡");
    }
}

这样就实现了重写,鸡类跟白切鸡类在live()方法中定义的行为不同,鸡类是一只命运有着无限可能的鸡,而白切鸡类的命运就是做成一只白切鸡。但是为什么还要有“父类引用指向子类对象”这个条件呢?

3. 父类引用指向子类对象

其实这个条件是面向对象的五大基本原则里面的里氏替换原则,简单说就是父类可以引用子类,但不能反过来。

当一只鸡被选择做白切鸡的时候,它的命运就不是它能掌控的。

Chicken c = new BaiqieChicken();
c.live();

运行结果:这是一只会被做成白切鸡的鸡为什么要有这个原则?因为父类对于子类来说,是属于“抽象”的层面,子类是“具体”的层面。“抽象”可以提供接口给“具体”实现,但是“具体”凭什么来引用“抽象”呢?而且“子类引用指向父类对象”是不符合“依赖倒置原则”的。当一只白切鸡想回头重新选择自己的命运,抱歉,它已经在锅里,逃不出去了。

BaiqieChicken bc = new Chicken();
bc.live();

 

多态的实现途径

多态的实现途径有三种:重写、重载、接口实现,虽然它们的实现方式不一样,但是核心都是:同一行为的不同表现形式

1. 重写

重写,指的是子类对父类方法的重新定义,但是子类方法的参数列表和返回值类型,必须与父类方法一致!所以可以简单的理解,重写就是子类对父类方法的核心进行重新定义。举个栗子:

class Chicken{
    public void live(String lastword){
        System.out.println(lastword);
    }
}
class BaiqieChicken extends Chicken{
    public void live(String lastword){
        System.out.println("这只白切鸡说:");
        System.out.println(lastword);
    }
}

这里白切鸡类重写了鸡类的live()方法,为什么说是重写呢?因为白切鸡类中live()方法的参数列表和返回值与父类一样,但方法体不一样了。

2. 重载

重载,指的是在一个类中有若干个方法名相同,但参数列表不同的情况,返回值可以相同也可以不同的方法定义场景。也可以简单理解成,同一行为(方法)的不同表现形式。举个栗子:

class BaiqieChicken extends Chicken{
    public void live(){
        System.out.println("这是一只会被做成白切鸡的鸡");
    }
    public void live(String lastword){
        System.out.println("这只白切鸡说:");
        System.out.println(lastword);
    }
}

这里的白切鸡类中的两个live()方法,一个无参一个有参,它们对于白切鸡类的live()方法的描述各不相同,但它们的方法名都是live。通俗讲,它们对于白切鸡鸡生的表现形式不同。

3. 接口实现

接口,是一种无法被实例化,但可以被实现的抽象类型,是抽象方法的集合,多用作定义方法集合,而方法的具体实现则交给继承接口的具体类来定义。所以,接口定义方法,方法的实现在继承接口的具体类中定义,也是对同一行为的不同表现形式

interface Chicken{
    public void live();
}
class BaiqieChicken implements Chicken{
    public void live(){
        System.out.println("这是一只会被做成白切鸡的鸡");
    }
}
class ShousiChicken implements Chicken{
    public void live(){
        System.out.println("这是一只会被做成手撕鸡的鸡");
    }
}

从上面我们可以看到,对于鸡接口中的live()方法,白切鸡类和手撕鸡类都有自己对这个方法的独特的定义。

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法