Abstrakte Klassen

Video

Mit dem Laden des Videos akzeptierst du die Datenschutzerklärung von YouTube. Wenn du die Menge an Daten reduzieren möchtest, die YouTube von dir sammelt, solltest du dich vorher aus deinem YouTube-Account ausloggen, das Speichern von Cookies für das Google-Ads-Programm deaktivieren und/oder Cookies im Browser blockieren.

YouTube immer automatisch laden
Inhaltsverzeichnis
Als Text lesen

Schau dir die folgende Klassenhierarchie an:

java_inheritance_uml_class_diagram_2.svg

Die Methode makeSound() wird nun in den beiden Unterklassen überschrieben, sodass jede Creature einen passenden Ton erzeugt. (Das könnte z.B. das Abspielen einer Sound-Datei in einem Computerspiel sein.) Welches Geräusch macht dann aber die Kreatur Creature selbst?

Diese Frage erscheint dämlich. Creature ist ja nur ein Oberbegriff für die beiden konkreten Unterklassen Alien und Sheep. Wir sollten in der Oberklasse eigentlich gar nicht gezwungen sein, eine spezielle Implementierung für diese Methode anzugeben. Wie lösen wir das Problem?

Abstrakte Klassen

Eine abstrakte Klasse ist eine Klasse, die selbst nicht instanziiert werden kann. Man kann also nicht über den Konstruktor ein neues Objekt dieser Klasse erzeugen.

  • Abstrakte Klassen werden mit dem abstract Keyword gekennzeichnet:

    public abstract class Creature {
    // ...
    }
    הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  • Eine abstrakte Klasse kann trotzdem einen Konstruktor haben. Dieser kann jedoch nur über super() (bzw. this()) aufgerufen werden, um beispielsweise Attribute zu setzen.
  • Eine abstrakte Klasse kann abstrakte Methoden enthalten, die zwar nur eine Methodensignatur enthalten, aber keinen Methoden-Körper:

    public abstract void makeSound(); // Kein Körper in geschweiften Klammern!
    הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  • Abstrakte Klassen bzw. Methoden kennzeichnet man in UML durch kursive Schrift, manchmal auch zusätzlich mit <<abstract>>:

    java_uml_class_diagram_abstract.svg

Durch verwendung von abstract Können wir also eine abstrakte Methode makeSound() in Creature deklarieren, ohne dabei angeben zu müssen, was bei der Ausführung passiert. Dieser Teil wird erst dadurch erledigt, dass wir die Methode in den Unterklassen überschreiben. Es kann dabei keine Probleme geben, weil durch abstract sichergestellt wird, dass niemals eine Instanz von Creature selbst existiert:

Creature creature = new Creature(); /* error: Creature is abstract;
cannot be instantiated */
creature.makeSound();
 
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Wann brauche ich das?

Du brauchst abstrakte Klassen immer dann, wenn du eine Oberklasse hast, bei der es keinen Sinn ergeben würde, wenn ein Objekt dieser Klasse (und nur dieser Klasse selbst) existieren würde.

Beispielsweise für die Klassen Car und GolfCar sollte Car vermutlich nicht abstract sein, weil ein Auto selbst ausreichend spezifisch ist um zu existieren. Wir können direkt in der Klasse Car angeben, wie beispielsweise das Fahrverhalten eines (gewöhnlichen) Autos funktioniert. Für das obige Beispiel mit Creature und Alien / Sheep erscheint es aber sinnvoll, Creature als abstract zu deklarieren, weil die Verhaltensweise einer allgemeinen Kreatur nicht genau genug beschrieben ist. Man müsste erst wissen, um welche Art von Kreatur genau es sich handelt, um bestimmte Methoden zu implementieren.

Du merkst selbst, dass es hier viel Spielraum für Diskussion gibt. Wie du deine Klassen modellierst bleibt letztlich dir überlassen. Am Ende ist am wichtigsten, dass der Code nicht nur funktional, sondern auch verständlich und erweiterbar ist.

Und noch einmal das Beispiel mit den geometrischen Formen (Zum letzten Mal, versprochen!):

java_inheritance_exercise_2_uml_class_diagram.svg

Überlege dir, welche der Klassen und welche der Methoden abstract sein sollten. Ändere deinen Code entsprechend.

Häufige Fehlerquellen
  • Überflüssiger Methodenkörper in abstrakter Methode: Entweder deine Methode ist abstract, oder deine Methode hat geschweifte Klammern mit einem Methodenkörper.
  • Klassen abstrakt, die nicht abstrakt sein sollten, oder umgekehrt
  • Methoden abstrakt, die nicht abstrakt sein sollten, oder umgekehrt
Lösungsvorschlag
/*
* Nur die Klasse Shape muss abstract sein. Bei allen anderen ändert sich nichts.
* Hierdurch sparen wir uns die überflüssige Implemetierung von area()
*/
public abstract class Shape {
protected double posX;
protected double posY;
/*
* Konstruktor bleibt bestehen, weil die Unterklassen diesen
* für den super() Aufruf benötigen
*/
public Shape(double posX, double posY) {
this.posX = posX;
this.posY = posY;
}
// Nicht abstrakt, weil für alle Unterklassen gleiche Ausführung
public void move(double dx, double dy) {
posX += dx;
posY += dy;
}
// Abstrakt, weil für jede Form anders
public abstract double area();
/*
* Nicht abstrakt, weil von allen Unterklassen gleichermaßen benötigt
* (für super.toString())
*/
@Override
public String toString() {
return "Figur an Position (" + posX + ", " + posY + ") mit Flächeninhalt "
+ area();
}
// ... Getter & Setter
}
 
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Dir gefällt meine Arbeit?

Unterstütze Mich
AllgemeinSocialRechtliches
HomeInstagramDatenschutz
ÜberYouTubeImpressum
TikTok
Ko-fi

Made with love by a former noob.

© 2022-2024 Timo Friedl