6.10 Abstrakte Klassen und abstrakte Methoden
 
Nicht immer soll eine Klasse sofort ausprogrammiert werden. Dies ist der Fall, wenn die Oberklasse lediglich Methoden für die Unterklassen vorgeben möchte, aber nicht weiß, wie sie diese implementieren soll. In Java gibt es dazu zwei Konzepte: abstrakte Klassen und Schnittstellen (engl. interfaces).
6.10.1 Abstrakte Klassen
 
Bisher haben wir Vererbung eingesetzt, und jede Klasse konnte Objekte bilden. Das ist allerdings nicht immer sinnvoll, nämlich genau dann, wenn eine Klasse nur in einer Vererbungshierarchie existieren soll. Sie kann dann als Modellierungsklasse eine Ist-eine-Art-von-Beziehung ausdrücken und Signaturen für die Unterklassen vorgeben. Eine Oberklasse besitzt dabei Vorgaben für die Unterklasse, das heißt, alle Unterklassen erben die Methoden. Ein Exemplar der Oberklasse selbst muss nicht existieren.
Um das in Java auszudrücken, setzen wir den Modifizierer abstract an die Typdefinition der Oberklasse. Von dieser Klasse können dann keine Exemplare gebildet werden. Ansonsten verhalten sich die abstrakten Klassen wie normale, sie enthalten die gleichen Eigenschaften und können auch selbst von anderen Klassen erben. Abstrakte Klassen sind das Gegenteil von konkreten Klassen.
Wir wollen die Klasse Gebaeude als Oberklasse für konkrete Gebäude abstrakt machen.
Listing 6.56
vb/Gebaeude.java
package vb;
abstract class Gebaeude
{
private int quadratmeter;
public int getQuadratmeter()
{
return quadratmeter;
}
protected void setQuadratmeter( int qm )
{
quadratmeter = qm;
}
}
Mit dieser abstrakten Klasse Gebaeude drücken wir aus, dass es eine allgemeine Klasse ist, zu der keine konkreten Objekte existieren. Es gibt in der realen Welt schließlich keine allgemeinen und unspezifizierten Gebäude, sondern nur spezielle Unterarten von Gebäuden, zum Beispiel Diskotheken, Kirchen und so weiter. Es ergibt also keinen Sinn, ein Exemplar der Klasse Gebaeude zu bilden. Die Klasse soll nur in der Hierarchie auftauchen, um alle konkreten Kleidungsklassen als Typ von Gebaeude darzustellen. Das zeigt, dass Oberklassen allgemeiner gehalten sind und Unterklassen weiter spezialisieren. Ein Versuch, ein Objekt der abstrakten Klasse zu bilden, führt zu einem Compilerfehler.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 6.7
In der UML werden abstrakte Klassennamen kursiv gesetzt
Die abstrakten Klassen werden normal in der Vererbung eingesetzt. Eine Klasse kann die abstrakte Klasse erweitern und auch selbst wieder abstrakt sein.
Das heißt, jemand könnte problemlos schreiben:
Disko d1 = new Disko();
Gebaeude d2 = new Disko();
Object d3 = new Disko();
Gebaeude[] diskos = new Gebaeude[]{ new Disko(), new Disko() };
6.10.2 Abstrakte Methoden
 
Das Schlüsselwort abstract leitet die Definition einer abstrakten Klasse ein. Eine Klasse kann ebenso abstrakt sein wie eine Methode. Eine abstrakte Methode definiert lediglich die Signatur, und eine Unterklasse implementiert dann irgendwann diese Methode. Die Klasse ist dann nur für den Kopf der Methode zuständig, während die Implementierung an anderer Stelle erfolgt. Durch abstrakte Methoden wird ausgedrückt, dass die Oberklasse keine Ahnung von der Implementierung hat und dass sich die Unterklassen darum kümmern müssen.
Erinnern wir uns an das Gebäude, das mit getTyp() eine Kennung liefern konnte. Wir haben damals für unbekannte Gebäude den Typ UNDEFINIERT vorgegeben. Doch schön ist das nicht! Es wäre viel angenehmer, wenn das Gebäude die Methode getTyp() abstrakt definieren würde. Dann könnten wir die Unterklassen – von denen wir Disko und Kirche definiert hatten – dazu auffordern, die Funktion zu überschreiben, damit sich konkrete Exemplare bilden lassen.
Listing 6.57
vc/Gebaeude.java
package vc;
public abstract class Gebaeude
{
public abstract GebaeudeTyp getTyp();
}
Die Definition einer abstrakten Methode wird mit einem Semikolon abgeschlossen.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 6.8
Auch abstrakte Methoden werden in UML kursiv gesetzt.
Ist mindestens eine Methode abstrakt, so ist es automatisch die ganze Klasse. Deshalb müssen wir das Schlüsselwort abstract ausdrücklich vor den Klassennamen schreiben. Vergessen wir das Schlüsselwort abstract bei einer solchen Klasse, erhalten wir einen Compilerfehler. Eine Klasse mit einer abstrakten Methode muss abstrakt sein, da sonst irgendjemand ein Exemplar konstruieren und genau diese Methode aufrufen könnte.
Versuchen wir, ein Exemplar einer abstrakten Klasse zu erzeugen, so bekommen wir ebenfalls einen Compilerfehler. Auch ein indirekter Weg über die Class-Methode newInstance() bringt uns nicht zum Ziel, sondern nur eine InstantiationException ein.
Vererben von abstrakten Methoden
Wenn wir von einer Klasse abstrakte Methoden erben, so haben wir zwei Möglichkeiten:
1. |
Wir überschreiben alle abstrakten Methoden und implementieren sie. Dann muss die Unterklasse nicht mehr abstrakt sein (wobei sie es auch weiterhin sein kann). Von der Unterklasse kann es ganz normale Exemplare geben. |
|
|
2. |
Wir überschreiben die abstrakte Methode nicht, sodass sie normal vererbt wird. Das bedeutet: Eine abstrakte Methode bleibt in unserer Klasse, und die Klasse muss wiederum abstrakt sein. |
|
|
Die Unterklasse Disko überschreibt die abstrakte Methode und nimmt das Abstrakte weg.
Listing 6.58
vc/Disko.java
package vc;
public class Disko extends Gebaeude
{
@Override
public GebaeudeTyp getTyp()
{
return GebaeudeTyp.GASTSTAETTE;
}
}

Implementiert eine Klasse nicht alle geerbten abstrakten Methoden, so muss die Klasse selbst wieder abstrakt sein. Eclipse bietet uns mit (Strg)+(1) an, entweder die Klasse abstrakt zu machen, oder alle geerbten abstrakten Methoden mit einem Dummy-Rumpf zu implementieren.
 Hier klicken, um das Bild zu Vergrößern
|