1. 程式人生 > >深入Java虛擬機器:多型性實現機制--動態單分派和靜態多分派

深入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中動態分派的方法呼叫,在執行期間,虛擬機器會根據呼叫者的實際型別呼叫對應的方法, 秩序根據這一個宗量就可以確定要呼叫的方法,所以是動態單分派(一個宗量)