2016-04-19 32 views
7

工作,我寫了下面的代碼:多態性不能在方法的參數在Java中

class Plane {} 
class Airbus extends Plane {} 

public class Main { 

    void fly(Plane p) { 
     System.out.println("I'm in a plane"); 
    } 

    void fly(Airbus a) { 
     System.out.println("I'm in the best Airbus!"); 
    } 

    public static void main(String[] args) { 

     Main m = new Main(); 

     Plane plane = new Plane(); 
     m.fly(plane); 

     Airbus airbus = new Airbus(); 
     m.fly(airbus); 

     Plane planeAirbus = new Airbus(); 
     m.fly(planeAirbus); 

    } 
} 

,其結果是:

I'm in a plane 
I'm in the best Airbus! 
I'm in a plane 

不出所料前兩個調用分別給出I'm in a planeI'm in the best Airbus!

Plane planeAirbus = new Airbus(); 

該方法將此對象視爲平面,即使真實對象是空中客車。即使當我添加abstractclass Plane,沒有什麼變化和上次調用的結果仍然是I'm in a plane

所以,問題是爲什麼多態性不能在工作方法的參數和調用?這有什麼目的嗎?它是如何工作的?

回答

4

這裏的問題是Java不支持方法參數的動態綁定。你看到的是靜態綁定,即在編譯時選擇要調用的方法的重載。

參見:Static Binding and Dynamic Binding

+0

是其他名字動態綁定雙調度還是有不同的概念? –

+1

我認爲雙重調度是不同的,但雙重調度通常也實現動態綁定,所以他們經常在一起看到。 – markspace

+1

Double Dispatch可以通過使用Visitor模式在Java中實現,因爲Java是一種靜態類型語言。 – Timmos

1

原因如下輸出的輸出:

I'm in a plane 
I'm in the best Airbus! 
I'm in a plane 

因爲它正在執行重載和重載是靜態多態性或編譯時Polymorhism。在重載時,類可以有多個具有相同名稱但參數類型不同的方法。在你的例子中PlanePlane planeAirbus = new Airbus();的類型

2

方法重載類型多態性是在Java編譯時確定的。

這意味着Java必須從它們表示的引用類型推斷出方法參數的類型,因爲它不知道它們在編譯時保存的對象的類型。

我們可以爭辯說,在這種情況下,很明顯Plane類型的引用持有Airbus類型實例。然而事情並不那麼簡單,因爲空客實例本身可能是一個方法參數,它可以保存任何子類實例或空客實例本身。

只有安全的賭注是不通過父鏈解析,並採取它的參考面值是實際的參考變量類型。這樣做的另一種方式可能是通過實現方法重載相同的重寫,並通過使用運行時綁定對象來解決。我不知道爲什麼它不這樣做,因爲它會導致方法超載和覆蓋更統一。

以下是從JLS Overloading

當一個方法被調用(§15.12)的參考文獻中,實際參數(任何顯式的類型參數和)的數量和編譯時間類型的參數的使用,在編譯時間,以確定將被調用的方法的簽名(第15.12.2節)。如果要調用的方法是實例方法,則將使用動態方法查找(第15.12.4節)在運行時確定要調用的實際方法。
1

Java重載是編譯時多態性。所以,當你聲明planeAirbusPlane時,它會調用fly(Plane)

其實類Main不應該知道PlaneAirbus可以飛。 它更好的設計:

public interface Flyable{ 
    void fly(); 
} 

public Plane implements Flyable{ 
    void fly(){ 
    //do something 
    } 
} 

public Airbus implements Flyable{ 
    void fly(){ 
     //do something 
    } 
} 

然後在Main

public static void main(String[] args) { 
    Flyable plane = new Plane(); 
    plane.fly(plane); 

    Flyable airbus = new Airbus(); 
    airbus.fly(airbus); 
}