深入Java虛擬機:多態性實現機制--動態單分派和靜態多分派

分派發生在編譯期和運行期,編譯期的分派爲靜態分派,運行期的爲動態分派。
編譯期是根據對象聲明的類型來選擇方法,運行期是根據對象實際類型來選擇方法。

  • 術語: 宗量(JVM虛擬機) , 什麼是宗量, 方法調用者和方法參數被稱爲宗量.(後面理解分派需要)
  • 靜態類型: 一個對象在聲明時的類型稱爲靜態類型,靜態類型再編譯器編譯時可知. 如 Animal a = new Dog(), 靜態類型爲Animal, 實際類型爲Dog.

Java 靜態分派(方法重載)

public class Test{
    //hi 方法重載
    public void hi(Father f , Father f1){
       System.out.println("ff");
    }

    public void hi(Father f , Son s){
      System.out.println("fs");
    }

    public void hi(Son s , Son s2){
      System.out.println("ss");
    }

    public void hi(Son s , Father f){
      System.out.println("sf");
    }

    public static void main(String[] rags){
       Father f = new Father();
       Father s = new Son();
       Test t = new Test();
       t.hi(f , new Father());
       t.hi(f , s);
       t.dost(s, f);
    }
}
class Father {}
class Son extends Father{}

執行結果沒有像預期的那樣輸出 ff、fs、sf而是輸出了三個 ff.

此處對於對象聲明時,靜態類型爲Father, 所以在編譯期間,編譯器會根據參數的靜態類型選擇要執行的方法,此時已經確定要執行的方法,所以在運行時調用的方法爲ff輸出的方法.這就是靜態分派.

Java 動態分派(方法重寫)

public class Test{

    public static void main(String[] rags){
        Father f = new Father();
        Father s = new Son();
        System.out.println("f.i " +f.i);
        System.out.println("s.i " +s.i);
        f.hi();
        s.hi();
    }
}

class Father {
        int i = 0 ;
        public void hi(){
            System.out.println("WelcomeFather!");
        }

}

class Son extends Father{
    int i = 9 ;
    public void hi(){
        System.out.println("WelcomeSon!");
    }

}

運行結果:f.i 0 s.i 0 WeclomeFather! WeclomeSon!

變量f,s在編譯器靜態類型爲Father,所以i來自於father, 在運行期間,JVM會根據實際類型來調用方法,s的實際類型爲Son,所以調用的方法是Son重寫的hi方法. 根據實際類型的方法調用爲動態分派.

單分派&多分派

單分派和多分派取決於宗量,  方法調用者和方法參數都是宗量.

Java中靜態分派的方法調用,首先確定調用者的靜態類型是什麼,然後根據要調用的方法參數的靜態類型(聲明類型)確定所有重載方法中要調用哪一個, 需要根據這兩個宗量來編譯, 所以是靜態多分派(多個宗量確定).
Java中動態分派的方法調用,在運行期間,虛擬機會根據調用者的實際類型調用對應的方法, 秩序根據這一個宗量就可以確定要調用的方法,所以是動態單分派(一個宗量)

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