Java: Polyphormie
Willemers Informatik-Ecke
Erweiterung (Vererbung) Java Abstrakte Klassen

Abstrakt gesehen bedeutet Polymorphie, dass Objekte, die in einer Vererbungsreihe stehen, wissen, welchen Typs sie wirklich sind, auch wenn sie über die Referenz einer Basisklasse angesprochen werden.

Die etwas flapsigere Formulierung wäre, dass ein Objekt sich erinnert, als was es einst mit new erzeugt wurde.

Beispiel Bass

Greifen wir auf ein Beispiel aus der Musik zurück. Für einen voluminösen Klang in einer Musikgruppe wird immer ein Bass benötigt. Ein Bass zeichnet sich durch tiefe Töne aus. Man könnte sagen, er brummt.

class Bass {
    void spieleTon() {
        System.out.println("brumm");
    }
}
Tatsächlich gibt es völlig verschiedene Arten von Bässen. In einer Rockband wird ein elektrischer Gitarrenbass bevorzugt, während eine Blasskapelle oft eher eine Tuba einsetzt. Da der Klang von E-Bass und Tuba zwar tief, aber durchaus unterschiedlich ist, wird man die Methode spieleTon in der Klasse EBass durch ein Donk überschreiben.
class EBass extends Bass {
    @Override
    void spieleTon() {
        System.out.println("donk");
    }
}
Eine Tubo wird ein etwas anderes Geräusch erzeugen. Wir lautmalen hier mal ein Prot.
class Tuba extends Bass {
    @Override
    void spieleTon() {
        System.out.println("prot");
    }
}

Zuweisung

Aufgrund der Zuweisungskompatibilität zur Basisklasse können Referenzen auf Bass auch Objekte von Tuba oder EBass aufnehmen.
Bass bass = new Bass();
Bass rock = new EBass();
Bass blas = new Tuba();
Interessant ist es nun, wenn man die verschiedenen Referenzen auffordert, einen Ton von sich zu geben.
bass.spieleTon(); // brumm
rock.spieleTon(); // donk
blas.spieleTon(); // prot
Obwohl alle Instrumente als Referenz der Klasse Bass definiert sind, erinnern sie sich offenbar noch daran, ob sie als Bass, EBass oder Tuba erzeugt worden sind und rufen die entsprechenden Methoden auf.

Basisklasse als Methodenparameter

Die Zuweisungskompatibilität ermöglicht es, den Basistyp als Parameter für eine Methode zu verwenden und als tatsächlichen Aufrufparameter eine beliebige Erweiterung zu übergeben.
public static void spielMalWas(Bass bass) {
    bass.spieleTon();
}
Die Methode spielMalWas kann nun die Methode spieleTon abspielen, ohne zu wissen, welche Erweiterung übergeben wurde. Es kann also eine Methode für alle Bässe geschrieben werden, die dann von allen Erweiterungen genutzt werden kann, solange sich die Methode auf die Methoden und Attribute der Basisklasse beschränkt.

Das Objekt kennt seinen Typ

Der Aufruf mit den entsprechenden Erweiterungen sorgt dafür, dass die Methode der verwendeten Erweiterung verwendet wird, obwohl die Methode spielMalWas nicht wissen kann, mit welcher Erweiterung sie aufgerufen wird. Also weiß das Objekt selbst, welchen Typs sie ist und sorgt für die Verwendung der korrekten Methode.

spielMalWas(rock);   // Ausgabe: donk
spielMalWas(blas);   // Ausgabe: prot
Dass das Objekt die Klasse speichert, mit der es erzeugt wurde, merkt man auch, wenn man ein Objekt per System.out.println ausgibt, wenn keine toString-Methode definiert ist:
System.out.println(rock);  // Ausgabe: EBass@4aa298b7
Hier sieht man den Klassennamen EBass, der für das new verwendet wurde. Hinter dem @-Zeichen steht eine hexadezimale Zahl, die die Position des Hauptspeichers repräsentiert.

Array

Sie können auch ein Array der Basisklasse anlegen. Anschließend können Sie neben Objekten der Basisklasse auch Elemente aller Erweiterungen eintragen.

final int BAESSE = 3;
Bass[] bassArray = new Bass[BAESSE];
bassArray[0] = rock;
bassArray[1] = bass;
bassArray[2] = blas;
for (int i=0; i<bassArray.length; i++) {
    spielMalWas(bassArray[i]);
}

Video


Erweiterung (Vererbung) Java Abstrakte Klassen