2016-04-19 6 views
7

ich in Methodenargumente in Java funktioniert schrieb das folgende Stück Code:Polymorphismus nicht

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); 

    } 
} 

Und das Ergebnis ist:

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

Wenig überraschend die ersten beiden Anrufungen geben I'm in a plane und I'm in the best Airbus! bzw. .

Plane planeAirbus = new Airbus(); 

Die Methode behandelt dieses Objekt als Ebene, obwohl das reale Objekt ein Airbus ist. Selbst wenn ich hinzufügen abstract-class Plane, ändert sich nichts und das Ergebnis des letzten Aufrufs ist noch I'm in a plane

Die Frage ist also, warum Polymorphismus nicht Methodenargumente und Anrufungen funktioniert in? Gibt es irgendeinen Zweck? Wie funktioniert es?

Antwort

4

Das Problem hier ist, dass Java dynamische Bindung von Methodenargumenten nicht unterstützt. Was Sie sehen, ist statische Bindung, d. H. Die Überladung der aufzurufenden Methode wird zur Kompilierungszeit gewählt.

Siehe auch: Static Binding and Dynamic Binding

+0

Ist der andere Name für dynamische Doppel Versand Bindung oder gibt es unterschiedliche Konzepte? –

+1

Ich denke Doppel-Versand ist anders, aber Doppel-Versand implementiert in der Regel auch dynamische Bindung, so dass sie oft zusammen gesehen werden. – markspace

+1

Double Dispatch kann in Java implementiert werden, indem das Besuchermuster verwendet wird, da Java eine statisch typisierte Sprache ist. – Timmos

1

Grund für die Ausgänge folgenden Ausgabe:

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

Weil es eine Überlastung durchführt, und eine Überlastung ist statischer Polymorphismus oder Compile-Zeit Polymorhism. Beim Überladen kann die Klasse mehrere Methoden mit demselben Namen, aber unterschiedlichen Argumenten verwenden. In Ihrem Beispiel Plane ist Typ für Plane planeAirbus = new Airbus();

2

Methode Überladung Typ Polymorphie wird zur Kompilierzeit in Java bestimmt.

Was bedeutet, dass Java hat Art des Verfahrensparameters vom Referenztyp zu schließen, die sie vertreten, da sie keine Ahnung von der Art des Objekts hat sie bei der Kompilierung halten.

Wir können argumentieren, dass es in diesem Fall ziemlich klar ist, dass die Referenz von Plane-Typ Airbus-Typ-Instanz enthält. Es ist jedoch nicht so einfach, da die Airbus-Instanz selbst ein Methodenparameter sein könnte, der jede Unterklasseninstanz oder Airbus-Instanz selbst enthalten könnte.

Nur sicher Wette ist nicht durch die Elternkette zu analysieren und nehmen Sie die Referenz für seine Nennwert, der tatsächliche Referenzvariablentyp ist. Eine andere Möglichkeit wäre das Implementieren einer Methode, die das Überladen derselben überschreibt, und das Verwenden der Laufzeitbindung von Objekten für die Auflösung. Ich weiß nicht, warum es nicht so gemacht wurde, weil es die Methode hätte überladen und uniformieren.

Im folgenden werden die Referenzen von JLS Overloading

Wenn eine Methode aufgerufen wird (§15.12), die Anzahl der aktuellen Argumente (und alle explizite Typargumente) und der Compiler-Typ der Argumente verwendet werden, um Kompilierzeit, um die Signatur der Methode zu ermitteln, die aufgerufen wird (§15.12.2). Wenn es sich bei der Methode, die aufgerufen werden soll, um eine Instanzmethode handelt, wird die tatsächliche Methode, die aufgerufen werden soll, zur Laufzeit mithilfe der Methode dynamic method lookup (§15.12.4) ermittelt.
1

Java-Überladung ist kompilierzeit Polymorphismus.Wenn Sie also planeAirbus als Plane deklarieren, wird fly(Plane) aufgerufen.

In der Tat, Klasse Main sollte nicht wissen, Plane und Airbus können fliegen. Bessere Gestaltung es:

public interface Flyable{ 
    void fly(); 
} 

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

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

Und dann in Main Klasse

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

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