天天看點

了解Java中的多态

多态是面向對象程式設計的三種基本特征之一。多态通過分離做什麼和怎麼做,将接口和實作分離開來。多态不僅能夠改善代碼的組織結構和可讀性,而且還能建立可擴充的程式。

封裝是通過合并特征和行為來建立新的資料類型,那麼,多态的作用就是消除類型之間的耦合關系。

向上轉型

對象既可以作為它自己本身的類型使用,也可以作為它的基類型使用。而這種把某個對象的引用視為對其基類型的引用的做法稱作向上轉型。

我們現在來看一個例子。

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. 任何域通路操作都将由編譯器解析,是以不是多态的。