Polymorphie Referenztyp ungleich Objekttyp

camaro

Mitglied
Hallo liebe Java-Community,

ich habe folgendes Verständnisproblem:
Beim Erstellen von Objekten einer Subklasse mit 'new' kann man ja als Referenzvariable den Typ der Superklasse verwenden, zB:
Code:
Tier t = new Hund();

Die Vorteile (Polymorphie, Wiederverwendbarkeit von Code, ...) verstehe ich, allerdings hat man dann die Einschränkung, dass nur mehr die Methoden, die auch in "Tier" definiert wurden auf das Objekt angewandt werden können (obgleich dann auch die überschriebene Methode der Subklasse ausgeführt wird). Also Methoden, die nur in der Klasse "Hund" implementiert sind, sind nicht mehr aufrufbar (es heißt dann immer, dass "der Compiler sie nicht sehen kann").

Nun verstehe ich nicht für wen oder was diese Einschränkung gut ist. Durch einen (Down-)Cast an beliebiger Stelle kann man diese Einschränkung ja wieder umgehen...

LG
camaro
 

Viktim

Bekanntes Mitglied
Wenn du nur ein eine Implementation von "Tier" hast, wie in deinem Beispiel mit "Hund" dann hast du recht und das bringt nicht viel.

Bei folgendem Beispiel ist es allerdings besser zu verstehen, was der Vorteil ist:
Java:
public class Programm {
  public static void main(String[] args) {
    List<Tier> tiere = new ArrayList<>();
    tiere.add(new Katze());
    tiere.add(new Hund());

    for (Tier tier : tiere) {
      tier.laufen();
    }
  }
}
Java:
public class Hund extends Tier {

  @Override
  public void laufen() {
    System.out.println("Der Hund läuft auch");
  }

}
Java:
public class Katze extends Tier {

  @Override
  public void laufen() {
    System.out.println("Die Katze läuft");
  }

}
Java:
public abstract class Tier {

  public abstract void laufen();

}

So hier siehst du, das du eine allgemeine Liste für Tiere machen kannst, in die du sowohl Hunde als auch Katzen tun kannst.
Aufrufen kannst du dabei immer die laufen Methode vom Tier, die ja aber von Hund und Katze anders überschrieben wird.
Und ausgeführt wird dann immer das Überschriebene.
 

camaro

Mitglied
Danke für das Polymorphie-Beispiel, das habe ich wie erwähnt schon verstanden.

Sollte jetzt aber ein abgeleitetes Tier eine neue Methode (die "Tier" nicht enthält) bekommen, kann diese Methode aber nicht über die allgemeine Tier-Referenzvariable angesprochen werden, zB:
Java:
public class Hund extends Tier {
     .
     .
     .

 
   public void gassiGehen() {
     .
     .
     .

   }

}

tier.gassiGehen(); würde dann zu einem Compiler-Fehler führen - wozu also diese Einschränkung? Wäre doch besser, man würde alle verfügbaren Methoden des Objekts verwenden können?
 

stg

Top Contributor
Wenn du weißt, dass man mit dem Tier auch Gassi gehen könnte, dann würdest du es vermutlich nicht essen, egal wie groß der Hunger ist.

Deklarierst du deine Variable als Hund, so bist du geneigt deinen Code so zu schreiben, dass du auch Methoden usw der Klasse Hund benutzt. Tust du das, so ist es dir später nicht oder nur schwer möglich, deinen Code so abzuändern, dass er auch für Katzen läuft.

Erstellst du selbst unmittelbar das Hund-Objekt, so ist es in vielen Fällen wirklich egal, ob die Variable nun vom Typ Tier oder vom Typ Hund ist. Oft erstellst du die konkrete Instanz aber nicht selbst sondern fragst eine andere Stelle danach oder bekommst sie von außerhalb übergeben / gesetzt. Ist deine Variable nun vom Typ Hund, so schränkst du deine Schnittstelle nach außen eventuell unnötig übermäßig stark sein.
Die Variablen-Deklaration hinterher von Tier auf Hund einzuschränken ist dann aber auch kein großer Aufwand. Andersherum hingegen oftmals schon. Als Grundregel kann man sich merken: Immer gegen die kleinste benötigte Schnittstelle programmieren. Verkehrt macht man damit erstmal nichts.
 

camaro

Mitglied
Ich denke, ich hab's jetzt verstanden.
Welches Objekt bzw. welchen Objekttyp man erhält, weiß man in komplexeren Programmen erst zur Laufzeit. Mein Beispiel mit "new Hund();" ist natürlich zu trivial. Der Compiler lässt von vornherein nur jene Methoden zu, die die Klasse des konkreten Objekts dann mit Sicherheit "kann".
Es gibt also aus Sicherheitsgründen gleich den Compiler-Fehler anstatt einen latenten, evtl. später auftretenden Laufzeit-Fehler.
 

Neumi5694

Top Contributor
Das kommt im Grunde hin. Du verallgemeinerst überall dort (Supertyp), wo verallgemeinert werden KANN.
Wenn du dann etwas spezifisches (Gassi gehen) machen willst, dann prüfst du vorher, ob dein Element das auch kann (also ein Hund ist oder von Hund ableitet) und castest dann. ((Hund)meinTier).gassigehen();
ODER aber, du verbesserst dein Klassenmodell noch.
Z.b. Warum gehen Hunde gassi?
1. Häuchen machen
2. Sportliche Betätigung.

Müssen alle Tiere Häufchen machen? Dann erstell eine abstrakte Methode Häufchen machen und ruf in der Implementation in "Hund" gassiGehen auf und bei der Katze rausLassen.

Dann ist dir als "Tier"-Besitzer egal, wie genau der Code (HarrHarr) zustande kommt, wichtig ist nur, dass er dann irgendwo liegt.


Kurz: In den meisten Fällen stellt sich die Frage, die du dir stellst, gar nicht, wenn die Datenmodelle richtig ausgearbeitet sind.
 

Ähnliche Java Themen

Neue Themen


Oben