Java多態

深入理解Java中的多態機制

在面向對象的程序設計語言中,多態是繼數據抽象和繼承之後的第三種基本特徵

引言:

多態通過分離做什麼和怎麼做,從另一個角度將接口和實現分離開來。多態不但能夠改善代碼的組織結構和可讀性,還能夠創建可擴展的程序--即無論在項目最初創建時還是在需要時添加新功能時都可以“生長”的程序。


本文目錄大綱:

一、什麼是多態

二、多態的類別

三、多態的產生方式

四、運行期多態必要條件

五、向上轉型

六、向下轉型

七、動態多態的適用範圍

八、多態的好處



1、什麼是多態

多態(Polymorphism),按字面的意思就是多種狀態簡單而通俗的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。


2、多態的類別

編譯期多態(靜態多態,早期綁定)和運行期多態(後期綁定);


綁定:將一個方法調用同一個方法主體關聯起來被稱做綁定。


前期綁定:在程序執行前綁定(由編譯器和連接程序實現),稱作前期綁定。它是面向過程的語言中不需要選擇就默認的綁定方式。列入C只有一種方法調用,那就是前期綁定。


後期綁定:在運行時根據對象的類型進行綁定。後期綁定也稱作動態綁定或運行時綁定。它通過某種特殊機制實現,即程序一直不知道對象的類型,但是方法調用機制調用機制能找到正確的方法體,並加以調用。


Java中除了static 方法和final 方法(private 屬於final 方法)之外,其他所有方法都是後期綁定。這意味着通常情況下,我們不必判定是否應該進行後期綁定--它會自動發生。


3、多態產生的方式


3.1、強制的:一種隱式做類型轉換的方法。


        強制多態隱式的將參數按某種方法,轉換成編譯器認爲正確的類型以避免錯誤。在一下的表達式中,編譯器必須決定二元運算符‘+’所應做的工作:        

[java] view plain copy

1.  int a = 1 + 2;  

2.  double d = 2.0 + 2.0;  

3.  String s = "abc" + "def";  

跟據需要判定"+ " 運算符所要進行的運算,(1和(2行中進行加法運算,(3中進行字符串連接運算

 

3.2、編譯期多態(重載  overload):


靜態多態性:包括變量的隱藏、方法的重載(指同一個類中,方法名相同(方便記憶),但是方法的參數類型、個數、次序不同,本質上是多個不同的方法)

舉例:

public class override{
      public void show( ){
      };
      public void show( int i){
           System.out.println("含參數的show方法 .");
      };
}


通過傳入不同參數,讓程序根據傳入的參數來表現出不同的狀態。進而實現多態。


3.3、運行期多態(重寫 override)


動態多態性:是指子類在繼承父類(或實現接口)時重寫了父類(或接口)的方法,程序中用父類(或接口)引用去指向子類的具體實例,從代碼形式上看是父類(或接口)引用去調用父類(接口)的方法,但是在實際運行時,JVM能夠根據父類(或接口)引用所指的具體子類,去調用對應子類的方法,從而表現爲不同子類對象有多種不同的形態。不過,程序代碼在編譯時還不能確定調用的哪一個類的方法,只有在運行時才能確定,故又稱爲運行時的多態性。


舉例:

public classsup {
   public void show(){
      System.out.println("show() in sup !");
   }
}
public classsub extendssup{
   public void show(){
      System.out.println("show() in sub !");
   }
}
public classClient {
 
   public static void main(String[] args) {
     
      supsp= new sup();
      subsb = new sub();
      sups = new sub();
     
      sp.show();
      sb.show();
      s.show();
   }
}


運行結果:

show() in sup !

show() in sub !

show() in sub !

 

第三行代碼,雖然編譯是sup類,但運行的卻是sub的show()方法。通過方法的重載,讓程序表現出不同的狀態,來體現程序的多態性。


4、運行期多態必要條件

一、要有繼承(包括接口的實現);
二、要有重寫;
三、父類引用指向子類對象。

 

5、向上轉型

          子類自有的方法不可見

         1)、代碼檢查不允許。

         2)、從實際意義上


在下面代碼中,s只能調用sup中曾聲明過的方法,而子類中新增加的所獨有的方法則並不可見,自然也無法調用。


sup s = new sub();

s.show();


 

6、向下轉型

          存在於繼承中,父類引用指向的對象實際是要轉型的子類引用的類型。

 

假設現在已經定義一個了Animal類,並且定義類Dog和類Cat繼承Animal.


[java] view plain copy

1.  1)  Animal a = new Dog();  

2.    

3.        Dog d = (Dog) a;    //正確  

4.    

5.  2) Animal a = new Cat();  

6.    

7.        Dog d = (Dog) a;    //拋異常    


對於一個由向上轉型而來的對象,如果對它實行向下轉型,需要知道該對象之前的類型。否則編譯器會報錯。如上述代碼所描述一樣。


7、動態多態的適用範圍


1、只適用於動態方法,對於變量不能被重寫(覆蓋),”重寫“的概念只針對方法,如 變量不能被重寫(覆蓋)

2、靜態static方法屬於特殊情況域不會有多態機制。所調用的方法根據編譯時採用的類型所確定。


下面通過代碼解釋:

/*
樣例1:
  classParent{
     int num = 3;
  }
 
  classChild extends Parent{
     int num = 4;
  }
*/
 
/*
樣例2:
class Parent{
 
}
 
class Child extends Parent{
    intnum = 4;
}
*/
 
/*
樣例3:
class Parent{
    void show(){
        System.out.println("ParentShow!");
     }
  }
 
  classChild extends Parent{
    void show(){
        System.out.println("ChildShow!");
     }
  }
*/
 
/*
樣例4:
class Parent{
    
  }
 
  class Child extends Parent{
    voidshow(){
        System.out.println("ChildShow!");
     }
  }
*/
 
 
class Parent{
    static void show(){
        System.out.println("ParentShow!");
     }
  }
 
  class Child extends Parent{
    static void show(){
        System.out.println("ChildShow!");
     }
  }
 
 
public class PC{
   public static void main(String[] args){
        Parentp = new Child();
        //樣例1:
        //System.out.println(p.num);//3, 輸出的是父類的num;
         
        //樣例2:
        //System.out.println(p.num);//錯誤: 找不到符號 num
         
        //樣例3:
        //p.show();//ChildShow!  輸出的是子類的方法!
         
        //樣例4:
        //p.show();//  錯誤: 找不到符號   p.show();
         
        //樣例5:
        p.show();//Parent Show!  運行父類的靜態方法。
   } 
}
 
/*


總結:

對象多態時:

1.成員變量:(不涉及覆蓋)

編譯時: 參考引用變量所屬的類中是否有調用的成員變量,有, 編譯通過,沒有,編譯失敗。

運行時: 參考引用變量所屬的類中是否有調用的成員變量, 並運行該類所屬中的成員變量。

簡單的說:編譯和運行都參考等號的左邊。


2.成員函數(非靜態):

編譯時:參考引用變量所屬的類中是否有調用的成員變量, 有, 編譯通過, 沒有,編譯失敗:

運行時:參考的是對象所屬的類中是否有調用的函數。

簡單的說:編譯看左邊, 運行看右邊。


3.靜態函數, 變量:

   編譯和運行都是參考左邊參數類型!

   其實靜態方法不存在多態, 靜態方法是屬於類的,我們說的是對象的多態!靜態方法直接用類名調用就好了,

   沒必要創建對象!

   靜態的方法只能被靜態的方法所覆蓋!

 

8、多態的好處


1.可替換性(substitutability)。多態對已存在代碼具有可替換性。例如,多態對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。


2.可擴充性(extensibility)。多態對代碼具有可擴充性。增加新的子類不影響已存在類的多態性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態功能。例如,在實現了圓錐、半圓錐以及半球體的多態基礎上,很容易增添球體類的多態性。


3.接口性(interface-ability)。多態是超類通過方法簽名,向子類提供了一個共同接口,由子類來完善或者覆蓋它而實現的。如圖8.3 所示。圖中超類Shape規定了兩個實現多態的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere爲了實現多態,完善或者覆蓋這兩個接口方法。


4.靈活性(flexibility)。它在應用中體現了靈活多樣的操作,提高了使用效率。


5.簡化性(simplicity)。多態簡化對應用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤爲突出和重要。



參考資料:http://www.cnblogs.com/hujunzheng/p/3872619.html

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