本文以Java多態的一些基本特徵來談一下分派調用。 java
在開始,依舊用經常使用方式,例子來引入,看一看下面例子的輸出: ide
/** * * @author Sel * * 2014.4.3 */ public class StaticDispatch { public void sayHello(Human guy) { System.out.println("hello, guy!"); } public void sayHello(Man guy) { System.out.println("hello, man!"); } public void sayHello(Women guy) { System.out.println("hello, women!"); } public static void main(String[] args) { Human man = new Man(); Human women = new Women(); StaticDispatch sd = new StaticDispatch(); sd.sayHello(man); sd.sayHello(women); } } class Human { } class Man extends Human { } class Women extends Human { }
hello, guy!
hello, guy!
函數
沒錯,程序就是你們熟悉的重載(Overload),並且你們也應該能知道輸出結果,可是爲何輸出結果會是這個呢? spa
先來談一下如下代碼的定義: code
Human man = new Man();
其中,變量的靜態類型和動態類型在程序中均可以發生變化,而區別是變量的靜態類型是在編譯階段就可知的,可是動態類型要在運行期才能夠肯定,編譯器在編譯的時候並不知道變量的實際類型是什麼(我的認爲可能也是由於要實現多態,因此纔會這樣設定)。 編譯器
如今回到代碼中,因爲方法的接受者已經肯定是StaticDispatch的實例sd了,因此最終調用的是哪一個重載版本也就取決於傳入參數的類型了。 虛擬機
實際上,虛擬機(應該說是編譯器)在重載時時經過參數的靜態類型來當斷定依據的,並且靜態類型在編譯期就可知,因此編譯器在編譯階段就可根據靜態類型來斷定究竟使用哪一個重載版本。因而對於例子中的兩個方法的調用都是以Human爲參數的版本。 編譯
Java中,全部以靜態類型來定位方法執行版本的分派動做,都稱爲靜態分派。 class
再來看動態分派,它和多態的另一個重要體現有很大的關聯,這個體現是什麼,可能你們也能猜出,沒錯,就是重寫(override)。 變量
例子以下:
/** * * @author Sel * * 2014.4.3 */ public class DynamicDispatch { public static void main(String[] args) { Human man = new Man(); Human women = new Women(); man.sayHello(); women.sayHello(); man = new Women(); man.sayHello(); } } abstract class Human { protected abstract void sayHello(); } class Man extends Human { @Override protected void sayHello() { System.out.println("hello man!"); } } class Women extends Human { @Override protected void sayHello() { System.out.println("hello women!"); } }
hello man!
hello women!
hello women!
其實由兩次改變man變量的實際類型致使調用函數版本不一樣,咱們就能夠知道,虛擬機是根據變量的實際類型來調用重寫方法的。
咱們也能夠從例子中看出,變量的實際類型是在運行期肯定的,重寫方法的調用也是根據實際類型來調用的。
咱們把這種在運行期根據實際類型來肯定方法執行版本的分派動做,稱爲動態分派。