Java基礎23:面向對象特徵之多態

前言:面向對象編程有三大特性:封裝、繼承和多態。封裝隱藏了類的內部實現機制,可以在不影響使用的情況下改變類的內部結構,同時也保護了數據。對外界而已它的內部細節是隱藏的,暴露給外界的只是它的訪問方法; 繼承是爲了重用父類代碼,兩個類若存在IS-A的關係就可以使用繼承,同時繼承也爲實現多態做了鋪墊。從一定角度來看,封裝和繼承幾乎都是爲多態而準備的,這是非常重要的知識點。多態(Polymorphism)按字面的意思就是“多種狀態”。多態指同一個實體同時具有多種形式,它是面向對象程序設計(OOP)的一個重要特徵。如果一個語言只支持類而不支持多態,只能說明它是是基於對象的,而不是面向對象的。

一、Java多態

Java中的多態性指同一個實體同時具有多種形式。具體體現在運行和編譯兩個方面。運行時多態是動態多態,其具體引用的對象在運行時才能確定。編譯時多態是靜態多態,在編譯時就可以確定對象方法使用的形式。

1、多態的分類

對於面向對象而言,多態分爲編譯時多態和運行時多態。其中編譯時多態是靜態的,主要是指方法的重載,它是根據參數列表的不同來區分不同的函數,通過編譯之後會變成兩個不同的函數,在運行時談不上多態;而運行時多態是動態的,它是通過動態綁定來實現的,也就是我們常說的多態性。

編譯時期多態(又叫靜態多態):

編譯時期的多態是靠重載實現的,根據參數個數,類型和順序決定的(必須在同一個類中)

運行時的多態(又叫動態多態):

在運行時JVM根據實際情況決定調用函數

2、運行時多態的概念

在前言中就提到了繼承在爲多態的實現做了準備:子類Child繼承父類Father,我們可以編寫一個指向子類的父類類型引用,該引用既可以處理父類Father對象,也可以處理子類Child對象,當相同的消息發送給子類或者父類對象時,該對象就會根據自己所屬的引用而執行不同的行爲,這就是多態。即多態性就是相同的消息使得不同的類做出不同的響應。  

簡而言之:多態是指允許不同類的對象對相同的消息做出響應,即同一消息可以根據發送對象的不同而採用多種不同的行爲方式。(發送消息就是函數調用)   

在Java中有兩種形式可以實現多態:基於繼承和基於接口。

a> 基於繼承實現的多態

Java基於繼承實現的動態多態有三個必要條件:繼承、重寫、向上轉型。

  •  繼承:在多態中必須存在有繼承關係的子類和父類。

  •  重寫:子類對父類中某些方法進行重新定義,在調用這些方法時就會調用子類的方法。

  •  向上轉型:在多態中需要將子類的引用賦給父類對象,只有這樣該引用才能夠具備調用父類的方法或子類的方法的能力。

    只有滿足了上述三個條件,我們才能夠在同一個繼承結構中使用統一的邏輯實現代碼處理不同的對象,從而達到執行不同的行爲。

 基於繼承實現的多態可以總結如下:對於引用子類的父類類型,在處理該引用時,它適用於繼承該父類的所有子類,子類對象的不同,對方法的實現也就不同,執行相同動作產生的行爲也就不同。

b>基於接口實現動態多態

    基於繼承實現多態是通過重寫父類的同一方法的幾個不同子類來體現的,那麼就可就是通過實現接口並覆蓋接口中同一方法的幾不同的類體現的。在基於接口實現的多態中,指向接口的引用必須是指定這實現了該接口的一個類的實例程序,在運行時,根據對象引用的實際類型來執行對應的方法。

3、實現動態多態的技術稱爲:動態綁定(dynamic binding)

是指在執行期間JVM判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。重載是靜態多態,是在編譯時綁定的。 與對象引用時引起的多態不同,後者是動態多態,是在運行時綁定的。

動態綁定,使用父類引用指向子類對象,再調用某一父類中的方法時,不同子類會表現出不同結果。 這樣的作用就是擴展性極好,玩過網遊的話應該知道, 遊戲中有不同的角色,它們都有一個父類,它們做相同動作時表現出來的效果就會不一樣,比如跑,魔法師的跑跟戰士的跑就不會一樣,這就是倆者都覆蓋了父類中的跑方法,各自有自己的實現,表現出來的多態。 如果有一天你想再加個角色,只用再寫一個類繼承該父類,覆蓋其中的跑方法就行了,其他代碼不用怎麼改,所以可維護性也很好。

4、多態的作用

消除類型之間的耦合關係;

簡化代碼,提高了代碼的複用性;

提高可擴展性。

1>因爲主類和其中調用的多個子類對象間的依賴不是直接的,而是通過接口或抽象類進行的,他們的耦合只在於接口層,而不是直接依賴於實現層。

2>把不同的子類對象都當作父類來看,可以屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的編程,極大減少了代碼量,以適應需求的不斷變化。賦值之後,父類型的引用就可以根據當前賦值給它的子對象的特性以不同的方式運作。

舉個栗子:

//不使用多態
Cat cat=new Cat();
cat.eat();
Dog dog=new Dog();
dog.eat();
Pig pig=new Pig();
pig.eat();
......

//使用多態
public void go(Animal animal)
{
  animal.eat();
}
go(new Cat());
go(new Cat());
go(new Cat());
......

//如果有100種動物,使用多態的代碼就提高代碼重用性,減少了代碼量

還有就是如果每個動物有100個方法 ,不使用多態豈不是每創建一個對象時都要調用100次,而多態給我們帶來了好處,我們只需在基類中寫出這100個方法,而在調用的時候只需將子類對象傳遞給基類對象,編譯器將會根據具體類的對象調用相應對象的方法,從而簡便了編程。

3>可擴展性:即父類爲形式參數,接收任意子類對象進行具體調用

增加新的子類不影響已存在類的多態性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章