In Java dienen abstrakte Klassen und Schnittstellen der Abstraktion. Abstraktion im Kontext der objektorientierten Programmierung bedeutet, dass Implementierungsdetails vor dem Endnutzer verborgen werden.
Durch Abstraktion ist es möglich zu erfahren, welche Funktionalitäten vorhanden sind, ohne jedoch zu wissen, wie diese konkret umgesetzt wurden.
Wir betrachten nun beide Konzepte genauer, um deren jeweilige Anwendungsbereiche besser zu verstehen.
Abstrakte Klasse
Eine abstrakte Klasse ist in Java eine Klasse, die nicht als Objekt instanziiert werden kann und die abstrakte Methoden enthalten kann. Eine abstrakte Methode ist eine Methode, für die bei der Deklaration keine Implementierung bereitgestellt wird.
Ein typisches Beispiel für eine abstrakte Klasse ist die Klasse `GraphicObject` aus dem Oracle Tutorial.
Um eine abstrakte Klasse zu erstellen, wird das Schlüsselwort `abstract` dem Schlüsselwort `class` vorangestellt.
abstract class AbstrakteKlasse { void ausfuehren() { System.out.println("ausgeführt"); } }
Eine abstrakte Klasse kann von anderen Klassen erweitert werden, d.h., es können Unterklassen erstellt werden, die auf der abstrakten Klasse aufbauen.
abstract class AbstrakteKlasse { void ausfuehren() { System.out.println("ausgeführt"); } } class ErweiterteAbstrakteKlasse extends AbstrakteKlasse { void neueMethode() { System.out.println("neu"); } @Override void ausfuehren() { System.out.println("überschrieben"); } }
Abstrakte Klassen werden genutzt, um gemeinsame Methoden für mehrere Klassen bereitzustellen, die eine gegebene abstrakte Klasse erweitern. Die Möglichkeit, abstrakte Methoden innerhalb abstrakter Klassen zu definieren, macht sie besonders nützlich für Klassen, die zwar ähnliche Methoden haben, deren Implementierung jedoch unterschiedlich sein soll. Betrachten wir dazu ein Beispiel:
Stellen wir uns ein Auto vor, das Funktionen wie Starten, Stoppen und Rückwärtsfahren besitzt. Diese Funktionen sind bei allen Automodellen gleich.
Wie aber verhält es sich mit Automatisierungsfunktionen, wie etwa dem autonomen Fahren? Die Implementierung dieser Funktionen kann für verschiedene Fahrzeugtypen unterschiedlich sein. Wir schauen uns an, wie man dies in einem objektorientierten Programm umsetzen kann.
Zunächst erstellen wir eine `Auto`-Klasse, die als Basis für mehrere Klassen unterschiedlicher Autotypen dient.
abstract class Auto { void starten() { // Implementierung System.out.println("Auto gestartet"); } void stoppen() { // Implementierung System.out.println("Motor gestoppt"); } void rueckwaertsfahren() { // Implementierung System.out.println("Rückwärtsgang aktiviert"); } abstract void autonomFahren(); }
Die Methoden `starten()`, `stoppen()` und `rueckwaertsfahren()` sind Methoden, die allen Autos gemeinsam sind. Daher ist ihre Implementierung bereits in der `Auto`-Klasse definiert. Ein bestimmter Autotyp kann jedoch eine eigene Implementierung für den autonomen Fahrmodus haben. Aus diesem Grund wird `autonomFahren()` als abstrakte Methode deklariert, die in den unterschiedlichen Klassen der verschiedenen Fahrzeugtypen jeweils auf eigene Weise implementiert werden kann.
class AutoTypA extends Auto { @Override void starten() { super.starten(); } @Override void stoppen() { super.stoppen(); } @Override void rueckwaertsfahren() { super.rueckwaertsfahren(); } @Override void autonomFahren() { // Eigene Implementierung System.out.println("Autonomes Fahren Typ A aktiviert"); } }
class AutoTypB extends Auto { // ...alle ähnlichen Methoden @Override void autonomFahren() { // Eigene Implementierung // Unterschiedliche Implementierung als AutoTypB System.out.println("Autonomes Fahren Typ B aktiviert"); } }
Es ist wichtig zu beachten, dass, wenn eine Unterklasse nicht alle abstrakten Methoden implementiert, die in der abstrakten Klasse definiert sind, sie selbst als abstrakte Klasse deklariert werden muss.
Schnittstelle
Eine Schnittstelle ist eine Möglichkeit, einer Klasse mitzuteilen, welche Methoden sie implementieren muss. Nehmen wir das Beispiel eines Autos, das bestimmte grundlegende Funktionen hat: es kann starten, sich bewegen und stoppen. Diese grundlegenden Funktionen sind bei allen Autos gleich.
Wenn Sie also die Schnittstelle eines Autos in einer Klasse implementieren, müssen Sie alle Methoden implementieren, damit das Auto ordnungsgemäß und sicher funktioniert.
Ähnlich wie bei abstrakten Klassen können wir keine Objekte einer Schnittstelle instanziieren oder erstellen. Sie kann als vollständig abstrakte Klasse betrachtet werden, da sie ausschließlich abstrakte Methoden enthält, d.h. Methoden ohne Implementierungskörper.
Eine Schnittstelle wird mit dem Schlüsselwort `interface` erstellt.
interface AUTO { void starten(); void stoppen(); void bewegen(); }
Eine Schnittstelle wird implementiert, indem das Schlüsselwort `implements` bei der Definition einer Klasse verwendet wird.
class AutoTypB implements AUTO { @Override public void starten() { System.out.println("gestartet"); } @Override public void stoppen() { System.out.println("gestoppt"); } @Override public void bewegen() { System.out.println("fährt"); } }
Ähnlichkeit
Die Gemeinsamkeit von abstrakten Klassen und Schnittstellen ist die Tatsache, dass beide nicht als Objekte instanziert werden können.
Unterschiede
Abstrakte Klasse | Schnittstelle | |
Vererbung und Implementierung | Nur eine abstrakte Klasse kann von einer Klasse geerbt werden. | Eine Klasse kann mehrere Schnittstellen implementieren. |
Variablentypen | Kann `final`, nicht-`final`, `static` und nicht-`static` Variablen haben. | Kann nur `static` und `final` Variablen haben. |
Methodentypen | Kann sowohl abstrakte als auch nicht-abstrakte Methoden enthalten. | Kann nur abstrakte Methoden enthalten, aber statische Methoden sind eine Ausnahme. |
Zugriffsmodifikatoren | Eine abstrakte Klasse kann einen Zugriffsmodifikator haben. | Methodensignaturen in der Schnittstelle sind standardmäßig `public`. Eine Schnittstelle hat keinen Zugriffsmodifikator. |
Konstruktoren und Destruktoren | Kann Konstruktoren und Destruktoren deklarieren. | Kann keine Konstruktoren oder Destruktoren deklarieren. |
Geschwindigkeit | Schnell | Langsam |
Unterschiede zwischen abstrakter Klasse und Schnittstelle
Wann verwendet man abstrakte Klassen und Schnittstellen?
Verwenden Sie abstrakte Klassen, wenn:
- Sie einige gemeinsame Methoden und Felder für mehrere Klassen bereitstellen möchten.
- Sie nicht-statische und nicht-finale Felder deklarieren möchten, um den Zustand des Objekts zu verändern, an das sie gebunden sind.
Verwenden Sie Schnittstellen, wenn:
- Sie das Verhalten einer Klasse definieren möchten, die die Schnittstelle implementiert, aber es ist nicht relevant, wie die Implementierung aussieht.
- Sie sicherstellen möchten, dass eine Klasse alle Methoden implementiert, um korrekt zu funktionieren.
Abschließende Bemerkungen
Schnittstellen werden vor allem für die Erstellung von APIs verwendet, da sie eine Struktur zur Implementierung von Funktionen bereitstellen können, ohne auf die konkrete Implementierung eingehen zu müssen.
Abstrakte Klassen werden im Allgemeinen genutzt, um gemeinsame abstrakte und nicht-abstrakte Methoden zwischen verschiedenen Klassen zu teilen, wobei die abstrakte Klasse erweitert wird, um die Wiederverwendbarkeit des Codes zu erhöhen.
Erfahren Sie mehr über Java mit Hilfe von Online-Kursen für Java. Bereiten Sie sich auf ein Vorstellungsgespräch zu Java vor? Hier sind einige Interviewfragen zur objektorientierten Programmierung.