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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章