深入Java虛擬機器:多型性實現機制--動態單分派和靜態多分派
阿新 • • 發佈:2018-11-20
分派發生在編譯期和執行期,編譯期的分派為靜態分派,執行期的為動態分派。
編譯期是根據物件宣告的型別來選擇方法,執行期是根據物件實際型別來選擇方法。
-
術語: 宗量(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中動態分派的方法呼叫,在執行期間,虛擬機器會根據呼叫者的實際型別呼叫對應的方法, 秩序根據這一個宗量就可以確定要呼叫的方法,所以是動態單分派(一個宗量)