Überladen in Java und multiple dispatch
Ich habe eine collection (oder eine Liste oder array-Liste), in der ich wollen, setzen Sie die beiden String-Werte und double-Werte. Ich beschloss, es eine Sammlung von Objekten und Verwendung von überladen ond Polymorphismus, aber ich habe etwas falsch gemacht.
Ich führen einen kleinen test:
public class OOP {
void prova(Object o){
System.out.println("object");
}
void prova(Integer i){
System.out.println("integer");
}
void prova(String s){
System.out.println("string");
}
void test(){
Object o = new String(" ");
this.prova(o); //Prints 'object'!!! Why?!?!?
}
public static void main(String[] args) {
OOP oop = new OOP();
oop.test(); //Prints 'object'!!! Why?!?!?
}
}
Im test scheint das argument Typ ist beschlossen, die zur Kompilierzeit und nicht zur Laufzeit. Warum ist das so?
Diese Frage ist in Bezug auf:
Polymorphismus vs Überschreiben vs. Überladen
Versuchen Sie zu beschreiben, Polymorphismus so einfach, wie Sie können
EDIT:
Ok, die Methode, die aufgerufen werden, ist beschlossen, zur compile-Zeit. Gibt es einen workaround um zu vermeiden, mit der instanceof
Betreiber?
- Denn das ist, wie Java das überladen funktioniert.
- Aber das Objekt ist ein String zur Laufzeit, und es ist eine definierte Methode für strings. Was mache ich falsch?
- Sie sind unter der Annahme, dass die Wahl der überladung zum Aufruf zur Laufzeit. Es ist nicht; es ist beschlossen, zur compile-Zeit, auf der Grundlage der statische Typ des Arguments.
- Überschreiben ist dynamisch, aber überladen ist statisch. Es ist design-Wahl.
- Danke. Wie kann ich tun, um zur Laufzeit entscheiden, welche Methode es aufgerufen?
- Verwenden Polymorphismus 🙂 oder das Besucher-Muster für multiple dispatch.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Diesem Beitrag Sekunden voo Antwort und gibt details über die/alternativen zu späte Bindung.
Allgemeinen JVMs verwenden Sie nur single dispatch: die runtime-Typ gilt nur für die Empfänger-Objekt; für die Methode Parameter, der statische Typ berücksichtigt. Für eine effiziente Umsetzung mit Optimierungen ist ganz einfach über Methode Tabellen (die sind ähnlich wie C++'s virtuelle Tabellen). Nähere Informationen finden Sie z.B. in die HotSpot-Wiki.
Wenn Sie möchten, multiple dispatch für Parameter, werfen Sie einen Blick auf
this.resend(...)
stattsuper(...)
zum aufrufen der meisten spezifischen überschriebene Methode der einschließenden Methode;Wenn Sie wollen stick mit Java, können Sie
Wert Versand:
Was Sie wollen, ist ein Doppel-oder allgemeiner multiple dispatch, etwas, das tatsächlich in die Praxis umgesetzt, die in anderen Sprachen (common lisp in den Sinn kommt)
Vermutlich der Hauptgrund, warum java nicht haben, denn es kommt zu Leistungseinbußen, da überlast Auflösung getan werden muss, zur Laufzeit und nicht kompilieren. Der übliche Weg, um dieses ist die Besucher-Muster - ziemlich hässlich, aber das ist, wie es ist.
Beim Aufruf einer Methode, die überlastet ist, Java nimmt die restriktivsten Typ basiert auf dem Typ des die variable an die Funktion übergeben. Es nicht den Typ der aktuellen Instanz.
Alte Frage, aber keine Antwort bietet eine konkrete Lösung in Java zu lösen das Problem auf saubere Art und Weise.
In der Tat, nicht leicht, aber sehr interessante Frage. Hier ist mein Beitrag.
Wie gesagt, in den ausgezeichneten @DaveFar Antwort, Java unterstützt nur single-dispatch-Methode.
In dieser Versand-Modus, der compiler Grenzen der Methode aufrufen, sobald der Zusammenstellung, indem man sich auf die deklarierten Typen der Parameter und nicht Ihre runtime-Typen.
Zu lösen, die Antwort in eine saubere Art und Weise und mit einem doppelten Versand, die wir haben, um Abstraktion, die für die manipulierten Daten.
Warum ?
Hier eine naive Besucher Ansatz zur Verdeutlichung des Problems :
Nun die Frage : wie kann ich besuchte Klassen kann sich auf die
visit()
Methode ?Der zweite Versand der double-dispatch-Umsetzung basiert auf der "this" - Kontext von der Klasse akzeptiert zu werden, besucht werden.
Also müssen wir eine
accept()
Methode inInteger
,String
undObject
Klassen zum ausführen dieser zweite Versand :Aber unmöglich ! Besuchten Klassen sind integrierte Klassen :
String
,Integer
,Object
.So haben wir keine Möglichkeit, diese Methode hinzuzufügen.
Und sowieso, wir wollen nicht hinzufügen, dass.
So zu implementieren, die double dispatch zu werden, müssen wir in der Lage, ändern Sie die Klassen, die wir wollen, übergeben Sie als parameter in der zweiten Versand.
Also anstatt zu manipulieren
Object
undList<Object>
als deklarierten Typ, wir manipulierenFoo
undList<Foo>
wo dieFoo
Klasse ist eine wrapper-hält der Benutzer den Wert.Hier ist die
Foo
Schnittstelle :getValue()
gibt der Benutzer den Wert.Es gibt
Object
als Rückgabetyp, aber Java unterstützt die Kovarianz gibt (seit der version 1.5), so könnten wir definieren einen spezifischen Typ für jede Unterklasse zu vermeiden downcasts.ObjectFoo
StringFoo
IntegerFoo
Hier ist die DisplayVisitor Klasse besuchen
Foo
Unterklassen :Und hier ist ein Beispiel-code zum testen der Implementierung :
Ausgabe :
Verbesserung der Umsetzung
Erfordert die tatsächliche Durchführung der Einführung einer speziellen wrapper-Klasse für jede buit-in der Art, die wir zusammenfassen möchten.
Wie besprochen, haben wir nicht die Wahl das betreiben eines Doppel-Versand.
Aber beachten Sie, dass die wiederholte code in Foo Unterklassen vermieden werden könnten :
Könnten wir in der Tat die Einführung eines abstrakten generischen Klasse, der hält, was der Benutzer Wert und bietet einen accessor zu :
Nun
Foo
sublasses sind leichter zu erklären :Und die
test()
Methode geändert werden sollte, zu erklären, ein Platzhalter-Typ (?
) für dieFoo
geben Sie in derList<Foo>
Erklärung.In der Tat, wenn Sie Sie wirklich benötigen, könnten wir vereinfachen die weitere
Foo
Unterklassen durch die Einführung von java-code-Generierung.Deklarieren diese Unterklasse :
könnte so einfach wie das deklarieren einer Klasse und hinzufügen einer Anmerkung auf:
Wo
Foo
ist eine benutzerdefinierte Anmerkung zur Verarbeitung an die compile-Zeit.dies ist nicht polymoprhism, Sie haben einfach überladen einer Methode und nannte es mit dem parameter der Objekt-Typ
Alles in Java ist ein
Object
/Objekt (außer primitiven Datentypen). Sie speichern strings und Ganzzahlen als Objekte, und wenn Sie dann rufen Sie dieprove
- Methode, Sie werden immer noch als "Objekte" bezeichnet. Sie sollten einen Blick auf dieinstanceof
Schlüsselwort. Überprüfen Sie diesen link