理解Java中的多态

来源:互联网 发布:餐馆软件 编辑:程序博客网 时间:2024/05/23 07:25

多态是面向对象程序设计的三种基本特征之一。多态通过分离做什么怎么做,将接口和实现分离开来。多态不仅能够改善代码的组织结构和可读性,而且还能创建可扩展的程序。
封装是通过合并特征和行为来创建新的数据类型,那么,多态的作用就是消除类型之间的耦合关系。

向上转型

对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用。而这种把某个对象的引用视为对其基类型的引用的做法称作向上转型。
我们现在来看一个例子。

package nxiangbo.polymorphic;abstract class Shape{    public abstract void draw();}class Circle extends Shape{    @Override    public void draw() {        System.out.println("draw Circle");    }}class Square extends Shape{    @Override    public void draw() {        System.out.println("draw Square");    }}class Line extends Shape{    @Override    public void draw() {        System.out.println("draw Line");    }}class Paint{    public void display(Shape shape){        shape.draw();    }}public class Canvas {    public static void main(String[] args){        Paint paint = new Paint();        Shape line = new Line();        paint.display(line);    }}

上面程序的运行结果为:draw Line
我们主要看display(Shape shape)这个方法和Canvas中的Shape line = new Line()代码,你可能会奇怪,编译器是如何知道Shape引用指向的是Line对象,而不是Circle和Square呢?实际上,编译器无法得知。为了了解这个问题,我们需要看一下绑定

方法调用绑定

将一个方法调用与同一个方法主体关联起来称作绑定。若在程序执行前进行绑定(由编译器和连接程序实现),称作前期绑定。前期绑定是面向过程语言的默认绑定方式,例如C语言。上述程序之所以令人迷惑,主要是因为前期绑定。因为,当编译器只有一个Shape引用时,它其实是无法知道究竟调用哪个方法才对。

其实,对于上述例子,Java运用的不是前期绑定,而是动态绑定。
动态绑定也称为运行时绑定、后期绑定:就是指在运行时根据对象的类型进行绑定。

如果一种语言要想实现动态绑定,就必须具有某种机制,以便在运行时能够判断对象的类型,从而调用正确的方法。。也就是说,编译器一直不知道对象的类型,但是方法调用机制能够找到正确的方法体,并加以调用。

在Java中,除了static和final(private方法属于final方法)方法外,其他的方法都是后期绑定。

为什么要将某个方法声明为final方法呢?除了防止其他人覆盖这个方法外,更重要的原因或许是:这样可以有效的“关闭”动态绑定。

由此可知,Java中的方法时通过动态绑定实现多态的。

可扩展性

由于有多态机制,我们可以根据自己的需要对系统添加任意多的类型,而不需要修改display()方法。当我们需要画一个三角形时,只需要添加三角形的类即可。

代码如下

class Triangle extends Shape{    @Override    public void draw() {        System.out.println("draw Triangle");    }}class Paint{    public void display(Shape shape){        shape.draw();    }}public class Canvas {    public static void main(String[] args){        Paint paint = new Paint();        Shape line = new Line();        paint.display(line);        Shape triangle = new Triangle();        paint.display(triangle);    }}

我们可以看到,程序正常运行,并画出Triangle。这正是我们期望多态所具有的特性。

需要注意的是

  1. 只有非private方法才会被覆盖。
  2. 任何域访问操作都将由编译器解析,因此不是多态的。
0 0