Vererbung/Polymorphie < Sonstige < Schule < Informatik < Vorhilfe
|
Status: |
(Frage) beantwortet | Datum: | 17:12 Di 18.01.2011 | Autor: | vivi |
Hallo,
wir haben ein Übungsblatt zum Thema Vererbung bekommen, allerdings kann ich teilweise die Lösungen nicht nachvollziehen.
Gegeben ist eine Klasse Basis mit folgenden Methoden:
public static void methode1()
{
System.out.println("A");
}
public void methode2()
{
System.out.println("B");
}
Weiterhin existiert eine Subklasse Ableitung extends Basis mit folgenden Methoden:
public static void methode1()
{
System.out.println("C");
}
public void methode2()
{
System.out.println("D");
}
In der main Methode eines Programmes findet man folgende Zeilen:
Basis instanz1 = new Basis();
Basis instanz2 = new Ableitung();
Ableitung instanz3 = new Ableitung();
Basis instanz4 = (Basis) new Ableitung();
Bei Ausführung der methoden
instanz2.methode1();
instanz4.methode2();
werden jeweils "A" und "D" ausgegeben.
1) Weshalb greift instanz4 auf die methode2() der Subklasse Ableitung obwohl es doch als (Basis) gecastet wurde? Und warum greift instanz2 auf die methode1() der Basisklasse zurück, obwohl es als "new Ableitung" erzeugt wurde? Werden die statische methode1() und die Instanzmethode methode2() anders behandelt bei einer Vererbung?
2) Worin besteht der Unterschied zwischen instanz2 und instanz4? Sind das nicht irgendwie beide Objekte der Klasse Basis (oder der Klasse Ableitung? Ich bin mir nicht sicher)?
3) Noch eine allgemeinere Frage: Wann kann ich ein Objekt einer Klasse casten? Wenn ich z.B. folgende Klassenhierarchie habe:
Klasse Wal unterteilt in
1) Zahnwal
2) Bartenwal
darf ich dann
Zahnwahl z = (Zahnwahl) new Wal();
schreiben oder geht das nur andersrum, also
Wal w = (Wal) new Zahnwal();
Was soll ich mir dann z.B. unter dem Befehl
Zahnwahl z = (Zahnwahl) null;
vorstellen? Ist die Zeile überhaupt gültig und was bewirkt sie?
Vielen Dank für Eure Hilfe,
Vivi
Ich habe die Frage auf keiner anderen Internetseite gestellt.
|
|
|
|
Hallo vivi,
eine Sache vorweg: auch wenn das die Musterlösung ist, sollte man sich keinesfalls diesen schlechten Programmierstil angewöhnen. Klassenvariablen und -methoden sollte man immer über "Klassenname.klassenvariable" oder "Klassenname.klassenmethode" aufrufen. Der Sinn von Klassenvariablen- und methoden besteht darin, dass auf sie zugegriffen werden kann, auch wenn keine Instanz ihrer Klasse existiert.
> 1) Weshalb greift instanz4 auf die methode2() der Subklasse
> Ableitung obwohl es doch als (Basis) gecastet wurde? Und
> warum greift instanz2 auf die methode1() der Basisklasse
> zurück, obwohl es als "new Ableitung" erzeugt wurde?
> Werden die statische methode1() und die Instanzmethode
> methode2() anders behandelt bei einer Vererbung?
Die Klassenmethode methode1() existiert sowohl in der Vater- wie auch in der Sohnklasse. Wie Klassenfelder können Klassenmethoden von einer abgeleiteten Klasse nicht überschrieben werden.
In der Zeile "Basis instanz2 = new Ableitung();" ist die Referenzvariable vom Typ Basis und sie zeigt auf ein Objekt vom Typ Ableitung. Gemäß dem Satz darüber ist es nur logisch, dass "A" ausgegeben wird.
Bei "Basis instanz4 = (Basis) new Ableitung();" ist der Cast (Basis) etwas irreführend und meint übrigens das gleiche wie "Basis instanz4 = new Ableitung();". Lässt man den Cast weg, übernimmt das der Compiler implizit, so wie das bei "Basis instanz2 = new Ableitung();" der Fall ist.
Bei "Basis instanz4 = (Basis) new Ableitung();" hat man eine Referenzvariable vom Typ der Vaterklasse, die auf ein Objekt vom Typ der Sohnklasse zeigt. Die Methode "public void methode2()" wird in der Sohnklasse überschrieben und mit "instanz4.methode2()" wird auf die Methode der Sohnklasse zugegriffen, daher die Ausgabe "D".
> 2) Worin besteht der Unterschied zwischen instanz2 und
> instanz4? Sind das nicht irgendwie beide Objekte der Klasse
> Basis (oder der Klasse Ableitung? Ich bin mir nicht
> sicher)?
Lass Dich nicht von dem schlechten Stil verwirren, den ich eingangs beschrieben habe.
Das Schema lautet bei Vererbung immer so:
Vaterklasse referenzvariable = new Sohnklasse()
Das funktioniert deshalb, weil die Sohnklasse mindestens über die Eigenschaften der Vaterklasse verfügt und an jeder Stelle im Programm, an der ein Objekt der Vaterklasse existieren soll, ein Objekt der Sohnklasse treten kann (das "Liskov substitution principle" in knappen Worten ).
> 3) Noch eine allgemeinere Frage: Wann kann ich ein Objekt
> einer Klasse casten? Wenn ich z.B. folgende
> Klassenhierarchie habe:
>
> Klasse Wal unterteilt in
> 1) Zahnwal
> 2) Bartenwal
>
> darf ich dann
> Zahnwahl z = (Zahnwahl) new Wal();
> schreiben oder geht das nur andersrum, also
> Wal w = (Wal) new Zahnwal();
Als kleine Übung kannst du ja folgende Zeile in die main-Methode Deiner Übungsaufgabe einfügen:
Ableitung instanz5 = new Basis();
Der Compiler wird hier garantiert meckern und einen expliziten Cast fordern.
Der Grund: an die Stelle eines Sohnobjektes kann kein Vaterobjekt treten, denn dieses verfügt über weniger Eigenschaften als das Sohnobjekt. Wenn Du aber an die entsprechende Stelle (Ableitung) einfügst, gibt der Compiler Ruhe.
> Was soll ich mir dann z.B. unter dem Befehl
> Zahnwahl z = (Zahnwahl) null;
> vorstellen? Ist die Zeile überhaupt gültig und was
> bewirkt sie?
Diese Zeile sollte nicht möglich sein - zumindest ergibt sie absolut keinen Sinn. Der Nullwert meint eigentlich nur den Zustand, dass kein Wert vorhanden ist beispielsweise wenn eine Referenzvariable noch nicht auf ein Objekt zeigt wie z.B.
Vaterklasse referenzvariable;
System.out.println(referenzvariable); // null auf dem Bildschirm
> Vielen Dank für Eure Hilfe,
> Vivi
Gruß
el_grecco
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 17:15 Do 20.01.2011 | Autor: | vivi |
Hallo el_grecco,
erst einmal vielen Dank für deine Erläuterungen :D
> Die Klassenmethode methode1() existiert sowohl in der
> Vater- wie auch in der Sohnklasse. Wie Klassenfelder
> können Klassenmethoden von einer abgeleiteten Klasse nicht
> überschrieben werden.
Weshalb erscheint dann beim Aufruf von
instanz3.methode1();
die Ausgabe "C"? Offensichtlich wurde hier für das Objekt instanz3 von der Klasse Ableitung die überschriebene Variante von methode1() verwendet, weshalb geht das jetzt für instanz3, nicht aber für instanz2 und instanz4?
> Als kleine Übung kannst du ja folgende Zeile in die
> main-Methode Deiner Übungsaufgabe einfügen:
>
> Ableitung instanz5 = new Basis();
>
> Der Compiler wird hier garantiert meckern und einen
> expliziten Cast fordern.
> Der Grund: an die Stelle eines Sohnobjektes kann kein
> Vaterobjekt treten, denn dieses verfügt über weniger
> Eigenschaften als das Sohnobjekt. Wenn Du aber an die
> entsprechende Stelle (Ableitung) einfügst, gibt der
> Compiler Ruhe.
Das heißt, dass ich im Grunde von Vater in Sohn explizit downcasten und von Sohn in Vater implizit upcasten kann. Dementsprechend wäre die Zeile z = (Zahnwal) new Wal(); ja korrekt, weil ich z aus der Sohnklasse nehme und mit (Zahnwal) explizit caste - liege ich damit richtig?
Ansonsten danke ich dir nochmals für die Erklärungen, sie haben echt weitergeholfen :)
Grüße,
Vivi
|
|
|
|
|
Hallo vivi,
> Hallo el_grecco,
>
> erst einmal vielen Dank für deine Erläuterungen :D
gern geschehen.
> > Die Klassenmethode methode1() existiert sowohl in der
> > Vater- wie auch in der Sohnklasse. Wie Klassenfelder
> > können Klassenmethoden von einer abgeleiteten Klasse nicht
> > überschrieben werden.
>
> Weshalb erscheint dann beim Aufruf von
> instanz3.methode1();
> die Ausgabe "C"? Offensichtlich wurde hier für das Objekt
> instanz3 von der Klasse Ableitung die überschriebene
> Variante von methode1() verwendet, weshalb geht das jetzt
> für instanz3, nicht aber für instanz2 und instanz4?
Klassenattribute und -methoden werden wie gesagt bei der Vererbung nicht überschrieben. Also wird auch die "methode1()", welche eine Klassenmethode ist, in der Sohnklasse nicht überschrieben. In diesem Fall wird die Klassenmethode der Vaterklasse nur verdeckt.
Das hier
Ableitung instanz3 = new Ableitung(); // Referenzvariable vom Typ Ableitung zeigt auf ein Objekt vom Typ Ableitung
instanz3.methode1();
ist nur eine Art Ersatzdarstellung (und sehr schlechter Stil!) für "Ableitung.methode1();". Klassenattribute- und methoden können ohne ein Objekt existieren. Anhand des Beispiels "Ableitung instanz3 = new Ableitung();" (sowie bei den anderen Beispielen mit static-Methoden) erkennst Du, dass offenbar nur der Typ der Referenzvariablen dafür ausschlaggebend ist, welche Methode verwendet wird.
> > Als kleine Übung kannst du ja folgende Zeile in die
> > main-Methode Deiner Übungsaufgabe einfügen:
> >
> > Ableitung instanz5 = new Basis();
> >
> > Der Compiler wird hier garantiert meckern und einen
> > expliziten Cast fordern.
> > Der Grund: an die Stelle eines Sohnobjektes kann kein
> > Vaterobjekt treten, denn dieses verfügt über weniger
> > Eigenschaften als das Sohnobjekt. Wenn Du aber an die
> > entsprechende Stelle (Ableitung) einfügst, gibt der
> > Compiler Ruhe.
>
> Das heißt, dass ich im Grunde von Vater in Sohn explizit
> downcasten und von Sohn in Vater implizit upcasten kann.
> Dementsprechend wäre die Zeile z = (Zahnwal) new Wal(); ja
> korrekt, weil ich z aus der Sohnklasse nehme und mit
> (Zahnwal) explizit caste - liege ich damit richtig?
Ist die Referenzvariable vom Typ einer Vaterklasse, so ist in keinem Fall ein expliziter Cast nötig.
Ist die Referenzvariable dagegeben vom Typ einer Sohnklasse, so ist ein expliziter Cast nur dann nötig, wenn das referenzierte Objekt vom Typ einer in der Vererbungshierarchie höher gelegenen Klasse ist.
Der Compiler erkennt aber wie gesagt Casting-Fehler und so gesehen kann man nicht viel falsch machen.
Google mal nach dem "Liskov substitution principle" und lies ein klein wenig darüber. Es mag einem als unwichtig erscheinen, aber in der objektorientierten Programmierung ist dieses Prinzip wirklich von zentraler Wichtigkeit.
> Ansonsten danke ich dir nochmals für die Erklärungen, sie
> haben echt weitergeholfen :)
Bei Fragen einfach nochmal melden.
> Grüße,
> Vivi
Gruß
el_grecco
|
|
|
|