Falconbyte unterstüzen
Betrieb und Pflege von Falconbyte brauchen viel Zeit und Geld. Um dir auch weiterhin hochwertigen Content anbieten zu können, kannst du uns sehr gerne mit einem kleinen "Trinkgeld" unterstützen.
Thema in Kurzform
public abstract class Tier { // Abstrakte Klasse
public abstract void bewegen(); // Abstrakte Methode
}
- Von abstrakten Klassen können keine Objekte erzeugt werden.
- Abstrakte Methoden haben keinen Rumpf und dürfen nur in abstrakten Klassen vorkommen. Sie müssen in einer Unterklasse überschrieben und implementiert werden.
- Abstrakte Klassen
- Abstrakte Methoden
- Übungen
Inhaltsverzeichnis
Abstrakte Klassen
Um den Sinn hinter dem Konzept der abstrakten Klassen zu verstehen, schauen wir uns zunächst einmal folgende einfache Vererbungshierarchie an:
Es ist naheliegend, dass wir von den Klassen Falke, Elefant und Eisbaer Objekte erzeugen. Wie sinnvoll ist es aber, die allgemeine Klasse Tier zu instantiieren? Wie können uns ganz konkret einen Falken, einen Elefanten oder einen Eisbären vorstellen. Aber ein allgemeines "Tier"? Wohl eher nicht.
Tatsächlich ist es so, dass die Klasse Tier viel zu unspezifisch ist, als dass wir davon Objekte erzeugen sollten. Denn wir wollen keine Tier-Objekte, sondern Falke-, Elefant- und Eisbaer-Objekte!
Das heißt natürlich nicht, dass die Klasse Tier unwichtig wäre. Ganz im Gegenteil: Sie ist absolut essentiell für unsere Vererbungslogik und Programmstruktur, zumal sie als Superklasse für andere Klassen dient.
Das Schlüsselwort abstract
Tier ist etwas Abstraktes, von dem es keine Objekte geben sollte. Um zu verhindern, dass eine Klasse wie Tier jemals instantiiert wird, müssen wir sie als abstract markieren:
public abstract class Tier {
//
}
Setzen wir also das Schlüsselwort abstract direkt hinter den Zugriffsmodifikator, haben wir die Klasse als abstrakte Klasse markiert, von der niemals(!) ein Objekt erstellt werden kann. Versuchen wir es dennoch, erhalten wir einen Compiler-Fehler.
Tier t = new Tier(); // ERROR!
Der Compiler meldet: 'Tier' is abstract; cannot be instantiated. Genau so muss das sein 😀
Konkrete Klassen
Klassen, die nicht abstrakt sind, nennt man konkrete Klassen. Davon können Objekte erzeugt werden.
Wenn wir in unseren Programmen die Vererbungsstruktur anlegen, sollten wir genau überlegen, welche Klassen abstrakt und welche konkret sind. Konkrete Klassen sollten so spezifisch wie möglich sein, dass die Objekterzeugung sinnvoll erscheint.
Erweitern wir unsere Vererbungshierarchie von oben nun ein wenig, um das Zusammenspiel von abstrakten und konkreten Klassen zu sehen.
Die Klasse Falke war zuerst noch eine konkrete Klasse. Da wir sie aber hier um zwei Unterklassen erweitert haben (Sakerfalke und Turmfalke) sind diese beiden spezifischer, d.h. konkreter, als Falke. Deshalb sollten wir Falke als abstract markieren und die Objekterzeugung von dieser Klasse verbieten. Falke ist damit eine abstrakte Unterklasse. Dasselbe Prinzip gilt auch bei den Klassen Baer, Grizzly und Eisbaer. Elefant wird nicht erweitert, auch wenn das natürlich ohne Weiteres denkbar wäre.
Abstrakte Methoden
Neben Klassen können auch Methoden als abstrakt markiert werden:
public abstract class Tier {
public abstract void bewegen();
}
In der abstrakten Klasse Tier haben wir eine abstrakte Methode bewegen() definiert. Dabei wird Schlüsselwort abstract direkt hinter den Zugriffsmodifikator gesetzt. Fällt Ihnen hier aber noch etwas anderes auf?
Richtig: Es fehlen die beiden geschweiften Methoden-Klammern { } und die Methode hat keinen Rumpf. Daraus ergeben sich folgende Regeln für abstrakte Methoden:
- Da abstrakte Methoden keinen Rumpf haben, können sie nicht ausgeführt werden.
- Abstrakte Methoden dürfen ausschließlich in abstrakten Klassen vorkommen (bei der ersten abstrakten Methode muss die Klasse ebenfalls mit abstract markiert werden). Oder anders ausgedrückt: In einer konkreten Klasse darf es keine abstrakten Methoden geben.
- Abstrakte Methoden müssen in einer Unterklasse überschrieben und implementiert werden (d.h. einen Methoden-Körper programmieren).
Würden wir abstrakte Methoden in konkreten Klassen zulassen, hieße das, dass wir Objekte mit nicht implementierten Methoden erzeugen könnten. Was für eine grausame Vorstellung 😨
Der Sinn von abstrakten Methoden
Beim Entwickeln von objektorientierten Programmen wissen wir schon im oberen Bereich des Vererbungsbaums, dass wir bestimmte Methoden für konkrete Unterklassen brauchen werden. Allerdings wäre es noch zu früh und die Oberklasse ist zu unspezifisch, um die konkrete Funktionsweise dieser Methoden für alle Unterklassen jetzt schon festzulegen. Diese Arbeit wird eine geeignete Unterklasse erledigen.
Denken Sie doch mal an die abstrakte Klasse Tier. Wir wissen, dass ein Tier sich bewegen kann (darum hat die Klasse auch eine Methode bewegen()). Allerdings ist Tier noch viel zu allgemein und vage, als dass wir wüssten, wie diese Bewegung genau sein soll. Es ist unmöglich, dass sich alle Tierarten gleich bewegen! Ein Falke etwa bewegt sich vollkommen anders als ein Elefant oder Bär. Eben deshalb hat die Methode zu diesem Zeitpunkt noch keinen Code und ist abstrakt.
Wie gesagt muss garantiert sein, dass eine abstrakte Methode von einer der Unterklassen implementiert und damit konkret wird. So können wir bewegen() etwa in der Klasse Elefant überschreiben und implementieren:
@Override
public void bewegen(){
System.out.println("Ich bewege mich schwer und oft langsam");
}
Elefant ist eine konkrete Klasse, da sie die von Tier geerbte abstrakte Methode bewegen() implementiert, selbst keine abstrakte Methode hat sowie nicht als abstrakte Klasse markiert wurde.
Wie sieht es nun aber mit Falke aus? In unserer Grafik oben ist die Klasse als abstract gekennzeichnet. Dies kann drei Ursachen haben:
- Die Methode bewegen() ist in dieser Klasse Falke nicht implementiert (sondern erst in den Unterklassen Sakerfalke und Turmfalke) oder
- bewegen() ist zwar implementiert, aber die Klasse definiert mindestens eine neue abstrakte Methode oder
- bewegen() ist zwar implementiert und es gibt auch keine neuen abstrakten Methoden, doch Falke ist als abstrakte Klasse markiert.
Das Gleiche gilt natürlich auch für abstrakte Klasse Baer.
Soviel zu den abstrakten Klassen und Methoden. Es wird Zeit, unser Wissen mit ein wenig Training zu festigen.
Übungen
einfach
Betrachten Sie folgende Vererbungshierarchie:
Die abstrakte Superklasse Fahrzeug hat eine abstrakte Methode. Alle übrigen Klassen sind konkret. In welchen dieser Klassen muss die abstrakte Methode also implementiert worden sein?
mittel
Welche der folgenden Klassen sind korrekte Definitionen für eine abstrakte Klasse (zwei richtige Antworten)?
class Owl {
abstract void hoot(); //(1)
}
abstract class Owl {
void hoot(); //(2)
}
abstract class Owl {
void hoot() { }; //(3)
}
abstract class Owl {
abstract void hoot() { } //(4)
}
abstract class Owl {
abstract void hoot(); //(5)
}
schwer
Stellen Sie sich vor, Sie sollen ein Programm für einen Computerfachmarkt entwickeln. Als Teil des Programms sind folgende Anforderungen gegeben:
- Schreiben Sie drei Klassen: Computer, DesktopPC und Notebook, wobei Computer die Superklasse von DesktopPC und Notebook ist.
- Schreiben Sie eine Methode int getPrice(), die den Preis für einen Computer zurückliefert.
- Schreiben Sie eine Methode void printDetails(), die die Details eines Computers printed.
Wie könnte der Code der Klasse Computer sinnvoll aussehen?