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 TypFruit
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 KlasseFruit
mittels dem Schlüsselwortabstract
als Abstrakt gekennzeichnet. - Die konkreten Klassen
Banana
undMango
definieren dann die konkrete Implementation der Methodeprepare
.
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 TypFruit
zuweisen? - Können Sie ein Objekt vom Typ
Mango
einer Variable vom TypFruit
zuweisen? - Können Sie ein Objekt vom Typ
Banana
einer Variable vom TypMango
zuweisen?
Haben Sie Fragen oder Bemerkungen? Schreiben Sie diese doch ins Forum.