Java多态简介

Java多态简介

一、什么是多态

面向对象程序设计的三大支柱是封装、继承和多态。

封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。

继承是为了重用父类代码。同时继承也为实现多态做了铺垫。

 

而多态,简单地说,意味着父类型的变量可以引用子类型的变量

 

详尽一点的理解,则是所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

 

二、简单的举例

package classdemo;

 

public class DuoTaiDemo {

     public static void main(String[] args) {

     Animal a = new Cat();

     a.eat();

     a.work();

     }     

}

    

    public class Animal {

     public void eat() {

         System.out.println("吃肉");

        }

     public void work() {

System.out.println("打工");

     }

    }

    

    class Cat extends Animal {

//     public void eat() {

//     System.out.println("吃鱼");

//     }

     public void work() {

     System.out.println("抓老鼠");

     }

    }

     Output:

吃肉

抓老鼠

三、例子分析

首先来简单梳理一下该程序的结构。

一段用于输出的主程序。一个父类Animal,一个Animal的子类Cat。

让我们来看如下这个略显奇怪的语句:

Animal a = new Cat();

这是一个非常经典的多态的用法,即父类的引用可以指向子类的对象。

 

向上转型

 

更为详细、深入的解释是"向上转型"。在这里Cat自动向上转型为Animal,因此作为Animal类型的a可以指向Cat的实例对象。

这有一个非常大的好处,子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。

但是!!!

向上转型存在一些缺憾,那就是它会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了。

依然以上述程序为例子。

可以注意到,在Animal类中拥有方法eat和work,而Cat中目前仅有work方法(eat被注释掉了)

输出的是Animal中的"吃肉"和Cat中的"抓老鼠"

 

为了理解"所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就鞭长莫及了。"这句话,

我们将Animal中的Work方法注释掉,这个时候会输出什么呢?

这个时候会报错!

而报错的语句正是a.work();

因为work是仅仅存在于子类Cat中的方法,对于多态而言,这是鞭长莫及的事情。

因此,想要调用子类中的方法,父类中可以不在方法中加入任何内容,却必须要有这个方法的存在。例如在Animal方法中增加一个public void work() {}语句就能够让程序顺利运行。

 

重写

在继承中就已经学习了重写(Override),在多态中依然会用到重写有关的内容。

在原程序中,Animal方法和Cat方法中均有Work方法

Animal中是        System.out.println("打工");

Cat中是         System.out.println("抓老鼠");

但是在输出中,输出的是Cat中的"抓老鼠",这是因为:

若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

 

而对于Cat中没有的方法eat,Animal类型的a则会自动调用父类Animal中的方法eat,输出"吃肉"。

可以验证,如果将Cat中的注释去掉,那么Animal中的eat自然就会被重写,

语句a.eat();

会输出Cat中的方法eat中的内容"吃鱼"

 

向下转型

在主程序中加入如下语句。

Cat c=(Cat)a;

c.eat();

c.work();

其中Cat c=(Cat)a;

就是一个向下转型的例子。有些时候为了完成某些父类没有的功能,我们需要将向上转型后的子类对象再转成子类,调用子类的方法,这就是向下转型。

但是请注意:不能直接将父类的对象强制转换为子类类型,只能将向上转型后的子类对象再次转换为子类类型。也就是说,子类对象必须先向上转型后,才能再向下转型

那么c.eat();

c.work();

的输出结果是什么呢?

注意到Cat类中并没有eat方法,因此c.eat调用了父类Animal中的eat方法,输出"吃肉";c.work则直接输出Cat中的work方法,输出"抓老鼠"。

程序如图:

虽然从结果上来看,

c.eat();   与  a.eat();

c.work();      a.work();

这两个语句的输出并无不同,但是其输出过程的本质却不尽相同,如果能彻底理解这两个"吃肉""抓老鼠"是怎么来的,相信你对多态已经有了一个新的了解!

posted @ 2021-05-10 22:31  软壳玩家  阅读(182)  评论(0)    收藏  举报