Java的靜態分派和動態分派

靜態分派:Java的靜態分派只涉及到方法的重載,也就是我們實際調用的是哪個重載方法實際上是在編譯期間確定的。

下面來舉例說明一下:

// 水果接口

interface Fruit{}

// 蘋果實現類

class Apple implements Fruit{

}

// 橘子實現類

class Orange implements Fruit{

}

//  重載方法

class EatFruit {

      void eat(Fruit fruit){

        System.out.println("吃水果");

       }

      void eat(Apple apple){

        System.out.println("吃蘋果");
       }

      void eat(Orange orange){

        System.out.println("吃橘子");
       }

}

// 調用

public static void main(String[] args) {

        EatFruit eatFruit = new EatFruit();

        Fruit apple = new Apple();

        Apple apple2 = new Apple();

        eatFruit.eat(apple);      // 輸出 "吃水果"

        eatFruit.eat(apple2)      // 輸出 "吃蘋果"

    }

這就說明了方法的重載實在編譯的時候就確定了分派到哪裏重載方法,編譯看左邊。apple因爲是用了Java的多態,使用了接口類型,所以最後
調用了參數是接口類型的eat重載方法。在編譯期間確定的分派就是靜態分派。


動態分派:就是在程序運行期間根據實際類型才決定具體調用的方法,就好像方法的重寫就是動態分派,重寫就是在運行時確定調用的。

                   Java的動態分派是單分派。

動態分派實例:

// 水果接口

interface Fruit{
     void show()
}

// 蘋果實現類

class Apple implements Fruit{
     void show(){

         System.out.println("我是蘋果");

 }}// 橘子實現類class Orange implements Fruit{

     void show(){

         System.out.println("我是橘子");

 }

}

// 調用

  Fruit apple = new Apple();

  apple.show(); // 輸出 "我是蘋果"

例子中我們創建Apple對象的時候,雖然也是使用的Fruit類型,但是在調用show方法的時候,虛擬機會根據對象的實際類型去動態選擇調用方法。這樣可以使我們定義更加通用的代碼,是的程序的擴展性更好。


因爲Java是單分派,所有在一次方法調用中,有兩個未知的具體類型的話,只能得知第一個的具體類型,是不可以同時都得到這兩個的具體類型的。

故,我們可以使用一種方法實現Java的多分派,也可以叫做僞多分派。

下面我們來看一種使用Enum實現的多分派,我們也使用經典的划拳例子說明:

public enum Outcome { WIN, LOSE, DRAW } // 這裏使用枚舉類型定義划拳結果
  
  
interface Item {  
    Outcome compete(Item it);     // 定義划拳方法
  
    Outcome eval(Paper p);        // 根據不同的出拳類型定義重載方法,這裏的重載方法需要在划拳方法中調用。   
  
    Outcome eval(Scissors s);  
  
    Outcome eval(Rock r);  
}  
  
class Paper implements Item {  
    /**這裏重點解釋一下
       所以假如我們通過Item paper = new Paper(); Item rock = new Rock();  paper.compete(rock); 調用的時候,
       Java的動態分派會根據具體的類型調用Paper的compete方法,方法中的this自然指代的是paper。但是,因爲Java是單分派,
       所以我們不會知道Item參數的具體類型是什麼。故我們通過調用參數it的eval方法,Java自然又會通過動態分派尋找到具體的類型,
       調用it的重載eval方法,這時知道了this的具體類型,自然會調用對應的重載方法,也就有了結果。就這樣,我們通過調用compete
       方法,實際上調用了兩個方法,每一個方法都會讓我們知道一個具體類型。**/
   public Outcome compete(Item it) {    
        return it.eval(this);
    }  
  
    public Outcome eval(Paper p) {  
        return DRAW;  
    }  
  
    public Outcome eval(Scissors s) {  
        return WIN;  
    }  
  
    public Outcome eval(Rock r) {  
        return LOSE;  
    }  
  
    public String toString() {  
        return "Paper";  
    }  
}  
  
class Scissors implements Item {  
    public Outcome compete(Item it) {  
        return it.eval(this);  
    }  
  
    public Outcome eval(Paper p) {  
        return LOSE;  
    }  
  
    public Outcome eval(Scissors s) {  
        return DRAW;  
    }  
  
    public Outcome eval(Rock r) {  
        return WIN;  
    }  
  
    public String toString() {  
        return "Scissors";  
    }  
}  
  
class Rock implements Item {  
    public Outcome compete(Item it) {  
        return it.eval(this);  
    }  
      
    public Outcome eval(Paper p) {  
        return WIN;  
    }  
  
    public Outcome eval(Scissors s) {  
        return LOSE;  
    }  
  
    public Outcome eval(Rock r) {  
        return DRAW;  
    }  
  
    public String toString() {  
        return "Rock";  
    }  
}  

Java的多分派(僞多分派) 實際上就是多次利用Java的單分派,變相的實現Java的多分派。




發佈了33 篇原創文章 · 獲贊 20 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章