Skip to main content

Vererbung und Abstrakte Klassen

Mit Interfaces haben wir eine Methode kennengelernt, um Operationen zu definieren, die von mehreren verschiedenen Datentypen umgesetzt werden können. Die im Interface definierten Methoden definieren gemeinsame Fähigkeiten, die alle Datentypen, die das Interface implementieren, aufweisen müssen. Diese Fähigkeiten können aber von Datentypen implementiert werden, die ansonsten konzeptionell nichts miteinander zu tun haben.

Eine stärkere Verbindung zwischen Datentypen können wir mittels Vererbung erreichen. Vererbung erlaubt uns, Datentypen in Hierarchien anzuordnen. Dadurch wird ausgedrückt, dass ein Konzept eine Spezialisierung eines allgemeineren Konzepts ist. Solche Hierarchien sind allgegenwärtig: Eine Ganzzahl ist eine Spezialisierung des Konzepts Zahl. Ein Sparkonto ist eine Spezialisierung des allgemeinen Konzepts eines Kontos. Eine Banane ist eine Spezialisierung des Konzepts einer Frucht.

Um solche Hierarchien umzusetzen, verwenden wir abstrakte Klassen. Eine abstrakte Klasse wird genau wie eine Klasse definiert. Wir schreiben aber das Schlüsselwort abstract vor die Klasse. Im folgenden Beispiel wird die abstrakte Klasse Fruit definiert:

abstract class Fruit {
String name;
String color;

public Fruit(String name, String color) {
this.name = name;
this.color = color;
}

void eat() { System.out.println("eat"); }
}

Wie wir sehen, können in einer abstrakte Klassen Felder, Methoden, und auch Konstruktoren genau wie in normalen Klassen definiert werden. Es ist jedoch nicht möglich, von abstrakten Klassen Instanzen zu erstellen. Mittels abstrakter Klassen wird nur das allgemeine Konzept definiert, welches dann von konkreten, spezialisierten Klassen umgesetzt wird.

In unserem Beispiel könnten wir uns eine konkrete Klasse Banana definieren, die von Fruit erbt.

class Banana extends Fruit {

public Banana() {
super("Banana", "yellow");
}
}

Um auszudrücken, dass die Klasse Banana von der Klasse Fruit erbt, nutzen wir das Schlüsselwort extends. Die Klasse von der geerbt wird, für Banana ist es hier Fruit, wird auch Superklasse genannt. Im Konstruktor der Klasse Banana, müssen wir als erste Anweisung den Konstruktor der Superklasse aufrufen. Dazu verwenden wir das Schlüsselwort super. Damit werden den Feldern name und color die entsprechenden Werte zugewiesen. Da Banana von Fruit erbt, müssen alle Eigenschaften, die für das allgemeine Konzept Fruit gelten, auch für die konkrete Spezialisierung Banana gelten. Wir können entsprechend auf Instanzen vom Typ Banana auf alle Methoden und Felder von Fruit zugreifen. Am besten, Sie vergewissern sich gleich selbst davon, indem Sie direkt selbst damit experimentieren:

Experimente

  • Versuchen Sie eine Instanz der Klasse Fruit zu erstellen.
  • Können Sie ein Objekt vom Typ Banana einer Variable vom Typ Fruit zuweisen?

Abstrakte Methoden

Genau wie bei Interfaces, ist es auch in abstrakten Klassen möglich, Methoden nur zu deklarieren, nicht aber zu implementieren. Dies macht Sinn, da im abstrakten Konzept ja gewisse Verhalten noch unklar sein können, und nur in den konkreten Klassen wohldefiniert sind. In unserem Frucht-Beispiel könnten wir in der Abstrakten Klasse Fruit eine Methode prepare definieren. Diese soll beschreiben, wie eine Frucht zubereitet werden kann. Wie diese aber umgesetzt werden soll, hängt von der konkreten Frucht ab. Nicht jede Frucht wird gleich zubereitet. In Java können wir dies wie folgt umsetzten:

abstract class Fruit {
String name;
String color;

public Fruit(String name, String color) {
this.name = name;
this.color = color;
}

abstract void prepare();
}


class Banana extends Fruit {

public Banana() {
super("Banana", "yellow");
}

void prepare() {
System.out.println("peel");
System.out.println("eat");
}
}

class Mango extends Fruit {

public Mango(String color) {
super("Mango", color);
}

void prepare() {
System.out.println("peel");
System.out.println("slice");
System.out.println("eat");
}
}

Beachten Sie folgende Punkte:

  • Die Methode prepare wurde in der Klasse Fruit mittels dem Schlüsselwort abstract als Abstrakt gekennzeichnet.
  • Die konkreten Klassen Banana und Mango definieren dann die konkrete Implementation der Methode prepare.

Experimente

  • Was passiert, wenn Sie in einer konkreten Klasse die Methode prepare nicht implementieren?
  • Können Sie ein Objekt vom Typ Banana einer Variable vom Typ Fruit zuweisen?
  • Können Sie ein Objekt vom Typ Mango einer Variable vom Typ Fruit zuweisen?
  • Können Sie ein Objekt vom Typ Banana einer Variable vom Typ Mango zuweisen?

Haben Sie Fragen oder Bemerkungen? Schreiben Sie diese doch ins Forum.