Frage zu Java Polymorphismus und Casting

8

Ich habe eine Klasse C. Klasse E erweitert es.

%Vor%

Warum ist

%Vor%

Bei weiterer Überprüfung: Obwohl numerische Konvertierungen dieselbe Syntax wie das Umwandeln von Objekten haben, kam es zu einiger Verwirrung. Auf jeden Fall gibt das Obige keine Kompilierung, sondern einen Laufzeitfehler - so kann eine Klasse in einigen Fällen in die Unterklasse geworfen werden (andernfalls würde der Code nicht kompiliert werden). Irgendwelche Beispiele, die jemand geben kann, wo das oben genannte funktioniert?

Und auch:

%Vor%

((M) k).getClass() gibt K . Warum das? Es wurde an die allgemeinere M ! Gegossen!

Angenommen, ich habe eine doIt () - Methode implementiert, die sowohl in M ​​als auch in K. implementiert ist.

%Vor%

gibt M's oder K's doIt ()?

Danke!

    
ooboo 04.07.2009, 15:48
quelle

9 Antworten

14

Betrachten Sie ein Beispiel aus der Praxis:

%Vor%

Alle Hunde sind Tiere, aber nicht alle Tiere sind Hunde. Daher ...

%Vor%

Ein Tier an einen Hund werfen kann nur getan werden, wenn es sich bei dem betreffenden Tier tatsächlich um einen Hund handelt. Andernfalls würde das Universum gezwungen sein, Eigenschaften, die einem Hund eigen sind (wagender Schwanz, Bellen usw.), auf ein Tier zu beziehen. Das Tier könnte eine Katze mit einzigartigen Eigenschaften sein (Schnurren, strenge Selbstreinigung, etc.). Wenn die Umwandlung nicht möglich ist, wird zur Laufzeit eine ClassCastException ausgelöst.

Niemand will einen schnurrenden Hund.

  

((M) k) .getClass () gibt K. Warum ist das? Es wurde an den allgemeineren M gegossen!

Sie haben k an M übergeben, aber alle Klassen haben eine getClass () -Methode. Die Klasse von k ist immer K, unabhängig davon, auf was sie ihren Verweis auf M bezieht oder nicht. Wenn du einen Hund in ein Tier wirfst und fragst, welches Tier es ist, antwortet es immer noch, dass es ein Hund ist.

Tatsächlich ist das Gießen in eine Superklasse überflüssig. Ein Hund ist bereits ein Tier und es hat alle Methoden eines Tieres sowie seine eigenen. Viele Codeanalyse-Tools wie FindBugs werden Sie über überflüssige Umwandlungen informieren, damit Sie sie entfernen können.

  

Angenommen, ich habe eine doIt () - Methode implementiert, die sowohl in M ​​als auch in K. implementiert ist.

     

((M) k) .doIt ();

     

gibt M's oder K's doIt ()?

K doIt () aus den gleichen Gründen wie oben. Die Besetzung wirkt auf die Referenz; Es transformiert ein Objekt nicht in einen anderen Typ.

  

Kannst du ein Beispiel geben, wenn das Casting (Dog doggy = (Hund) myAnimal) Sinn macht?

Sicher kann. Stellen Sie sich eine Methode vor, die eine Liste von Tieren zur Verarbeitung erhält. Alle Hunde müssen für einen Spaziergang genommen werden, und alle Katzen müssen mit einem Vogel-förmigen Spielzeug gespielt werden. Dazu rufen wir die takeForWalk() -Methode auf, die nur bei Dog existiert, oder die play() -Methode, die nur bei Cat.

existiert %Vor%     
banjollity 04.07.2009, 15:58
quelle
8

Sie können keine Objekte in Java darstellen.

Sie können Referenzen in Java umsetzen.

Das Umsetzen einer Referenz ändert nichts an dem Objekt, auf das sie verweist. Es erzeugt nur eine Referenz eines anderen Typs, die auf dasselbe Objekt wie die ursprüngliche Referenz verweist.

Das Umsetzen primitiver Werte unterscheidet sich von Casting-Referenzen. In diesem Fall ändern sich die Werte .

    
Joachim Sauer 04.07.2009 15:55
quelle
7

Nur weil E C erweitert, wird C kein E ... E, andererseits ist es ein C

Bearbeiten: Um Marks Kommentar unten zu erweitern ... Nur weil jede Frau ein Mensch ist, sind nicht alle Menschen Frauen. Alle Menschen teilen die "menschliche Schnittstelle" mit Beinen, Händen, Gesichtern usw. Frauen erweitern sie mit Funktionen, die gute Gefühle zurückgeben, wenn Sie Diamanten und Gold zur Verfügung stellen.

Der Int = & gt; double conversion ist nicht einmal verwandt, da es sich nicht um eine Klasse handelt, sondern um eine Umwandlung, die den Compiler anweist, alles in x in y zu speichern (was zufällig ein Doppel ist).

  

((M) k) .getClass () gibt K.

weil k immer noch ein K ist, auch wenn Sie es auf ein M oder ein Objekt (oder etwas anderes, was es gerade ist) werfen.

Edit: Ich denke, die Verwirrung hier ist, weil du denkst, dass k ein "M" wird, wenn du es machst, es nicht tut. Du behandelst es nur als M. Wenn du jemanden fragst, der ein "Hundebesitzer" ist, welche Art von Rasse es ist, wird er nicht "Es ist ein Hund" zurückgeben, der Grund ist einfach, dass die getBreedName () -Methode wahrscheinlich in der Unterklasse LabradorOwner außer Kraft gesetzt wurde, um zurückzukehren. Labrador". Dasselbe gilt für getClass (), es gibt die Klasse der Implementierung zurück. Es wird kein M sein, sondern ein K, das zufällig ein M ist, nur weil K M erweitert.

    
Fredrik 04.07.2009 15:51
quelle
4

Der int / double ist nicht verwandt; das ist eine Konvertierung, keine Umwandlung - es gibt keine Beziehung zwischen int und double .

Zu der Frage; Das Objekt eines Typs ist bei der Erstellung festgelegt. Ein Objekt , das ein C ist, ist nicht (und kann niemals sein) ein E . Sie können jedoch treat mit E als C behandeln, da die Vererbung "is a" darstellt. Zum Beispiel:

%Vor%

Hier haben wir immer noch nur ein Objekt - einfach, dass die Variable c es als C ansieht, also werden keine spezifischen Methoden für E verfügbar gemacht (obwohl das Objekt an E ).

Wenn wir dann hinzufügen:

%Vor%

Dies ist eine Typprüfung; Auch hier haben wir das Objekt nicht geändert, aber um c in eine E Variable zu setzen, müssen wir dem Compiler / Runtime beweisen, dass es wirklich ist ein E . Wir haben das im ersten Beispiel nicht benötigt, da es schon beweisen kann, dass E auch ein C ist.

Gleichermaßen, mit getClass() - ändert sich der Cast nur so, wie der Compiler über das Objekt denkt; Sie haben das Objekt selbst nicht geändert. Es ist immer noch ein K .

Sie müssen Variablen von Objekten trennen. Die Besetzung spricht über die Variablen ; Sie ändern das Objekt nicht.

    
Marc Gravell 04.07.2009 15:54
quelle
1

Um Frederiks Antwort hinzuzufügen, wird das Objekt nicht geändert. Objekt kann auch nur in einen Typ umgewandelt werden, der bereits vorhanden ist (der Compiler weiß zu diesem Zeitpunkt nicht) Deshalb werden unmögliche Gussformen niemals akzeptiert:

%Vor%

wird nicht kompiliert, weil der Compiler weiß, dass es nicht möglich ist.

    
Jorn 04.07.2009 15:57
quelle
1
  

((M) k) .getClass () gibt K. Warum ist das? Es wurde an den allgemeineren M gegossen!

Eine nützliche Analogie (die ich von Bill Venners Website artima.com bekommen habe), die helfen könnte, die Verwirrung zu beseitigen, ist, dass der Unterschied zwischen Klassen und Objekten der Unterschied zwischen dem Entwurf eines Architekten und dem tatsächlichen Haus ist. Der Entwurf existiert auf Papier und ist ein Konzept, während das Haus im wirklichen Leben existiert. Sie können mehr als ein Haus nach demselben Bauplan bauen lassen.

Wie ist das relevant für diese Frage? Nehmen wir an, es gibt einen McMansion Blueprint und einen McMansionWithHeatedPool Blueprint. A McMansionWithHeatedPool ist eine Erweiterung von McMansion mit einem beheizten Pool.

Wenn Sie nun ein echtes McMansionWithHeatedPool für dieses Objekt sehen:

  1. Konzeptionell (d. h. wenn Sie sich die Baupläne des Architekten ansehen) würden Sie sehen, dass ein McMansionWithHeatedPool eindeutig auch ein McMansion ist. Daher ist der Upcast erlaubt. (Aus demselben Grund kann ein McMansion Objekt nicht in einen% code% umgewandelt werden: kein beheizter Pool!)

  2. (( McMansionWithHeatedPool ) k) .getClass () gibt McMansion , weil k immer noch McMansionWithHeatedPool ist. Der Typcast ist auf dem Ausdruck, nicht auf dem Objekt.

vijucat 09.07.2009 03:55
quelle
1
  

"Wenn der Compiler es als M behandelt, sollte es die Methoden von M ausführen."
  Der Compiler behandelt die Referenz als M. Die Instanz , auf die die Referenz verweist, ist vom Typ K, nicht M. Sie können die Referenz nicht umsetzen und annehmen, dass dies die Instanz bedeutet wird plötzlich das Verhalten ändern. Der Compiler stellt sicher, dass die Methode, die Sie für die angegebene Referenz aufrufen, existiert. Es hat nichts damit zu tun, welche Implementierung aufgerufen wird, nur dass eine Implementierung existiert.

    
hameltime 09.07.2009 04:08
quelle
0

Bei der ersten Frage können Sie keine Oberklasse in eine Unterklasse umwandeln, da eine Unterklasse Elemente hinzufügt, die die Oberklasse nicht besitzt. Wie soll der Compiler wissen, welche Werte er beim Casting angeben soll? Grundsätzlich ist ein E ein C, aber ein C ist kein E.

getClass () ruft den Typ des Objekts im Speicher ab. Casting nach M verbirgt einfach die Tatsache, dass es ein K ist, es ändert nicht das zugrunde liegende Objekt.

    
Sean 04.07.2009 15:55
quelle
0

Durch das Umwandeln eines Objekts wird das Objekt nicht in das Objekt umgewandelt, das umgewandelt wird. Stattdessen kann ein anderer Klassenverweis, der durch Vererbung mit ihm verknüpft ist, auf das Objekt verweisen.

Zum Beispiel C extends E . Und beide haben eine Methode myName(); . Wenn Sie sagen

%Vor%

Sie rufen C myName() method auf und wenn Sie auch

sagen %Vor%

Sie haben dem Compiler gerade gesagt, dass Sie auf E mit dem Referenztyp C verweisen sollten.

    
Elvis chidera 29.06.2012 14:42
quelle

Tags und Links