面向对象系列之多态

133 阅读3分钟

这是我参与更文挑战的第6天,活动详情查看: 更文挑战

说完继承,我们再来聊聊多态!

多态字面上解释,就是程序可以有多个运行状态。

既然是运行状态,那其实更多的是强调方法的使用。

重载与覆写

方法在两种情况下使用会比较特别,一种是 overload(重载),overload 方法是本类内的新方法,方法名一样,但是参数的类型或数量不同。这种方法没有特殊的标识,通过类内方法是否重名判定。

另外一种就是 override(覆写),override 方法是继承关系下子类的新方法,方法签名和父类完全相同。这种方法都会有 @Override 注解的标识。

package cn.java4u.oo.polymorphism;

/**
 * 动物
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Animal {


    /**
     * 与 eat(String food) 重载
     */
    public void eat() {
        System.out.println("Animal.eat");
    }

    /**
     * 与 eat() 重载
     *
     * @param food 食物
     */
    public void eat(String food) {
        System.out.println("Animal.eat: " + food);
    }

    /**
     * 覆写
     *
     * @return 字符串
     * @see java.lang.Object#toString
     */
    @Override
    public String toString() {
        return "Animal " + super.toString();
    }
}

举个例子,Animal 类里两个 eat 方法就互为重载方法,toString 方法就是相对于父类方法 java.lang.Object#toString 的覆写方法。

多态就发生在覆写这种场景下。针对某个类型的方法调用,它真正执行的方法取决于运行时期实际类型的方法。比如下面这段代码,当声明类型为 Object ,初始化类型为 Animal 时,你觉得输出的是 AnimaltoString 方法,还是 ObjecttoString 方法?

package cn.java4u.oo.polymorphism;

/**
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class PolymorphismTest {

    /**
     * 打印对象
     *
     * @param scene 打印场景
     * @param obj   obj
     */
    public static void printObjectString(String scene, Object obj) {

        System.out.println(scene + ": " + obj.toString());

    }

    public static void main(String[] args) {

        // 父类引用初始化父类对象并打印
        Object rootObj = new Object();
        printObjectString("父类引用初始化父类对象", rootObj);

        // 子类引用初始化子类对象并打印
        Animal animal = new Animal();
        printObjectString("子类引用初始化子类对象", animal);


        // 父类引用初始化子类对象并打印
        Object animalWhenParentRef = new Animal();
        printObjectString("父类引用初始化子类对象", animal);
        
    }
}

答案是子类 AnimaltoString 方法!

父类引用初始化父类对象: java.lang.Object@60e53b93
子类引用初始化子类对象: Animal cn.java4u.oo.polymorphism.Animal@5e2de80c
父类引用初始化子类对象: Animal cn.java4u.oo.polymorphism.Animal@5e2de80c

实际类型为 Animal 引用类型为 Object ,调用 toString 方法时,实际上是子类的。因此我们可以得出结论:Java 的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。这种特性就是多态

你会发现 printObjectString 方法的第二个参数,即便声明的是 Object ,实际运行的时候,却可以是它的子类覆写方法。

至此,我们也理出了 Java 实现多态三要素,那就是 继承覆写向上转型。即两个类之间有继承关系,某个类覆写了父类的某个方法,方法的引用会指向子类的实现处。

总结

面向对象语言这个系列呢,我们分析了面向对象的概念和思想。接着基于面向对象的特征:抽象、封装、继承和多态,我们又详细的分析了在 Java 中的体现方式,并伴有很多样例代码辅助学习。看完这个系列,想必你对面向对象这个东西会有更全面的了解。

好啦,本系列的分享就到这里,如果各位喜欢我的分享,请务必三连,点赞分享收藏,关注我,这会对我有非常大的帮助。

我们下期再见。