Menu
Coddy logo textTech

Abstrakte Klassen vs. Interfaces

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 38 von 87.

Da du nun sowohl abstrakte Klassen als auch Schnittstellen verstehst, stellt sich eine häufige Frage: Wann solltest du die eine der anderen vorziehen? Die Wahl hängt davon ab, was du modellieren möchtest.

Verwende eine abstrakte Klasse, wenn Klassen eine gemeinsame Basisklasse mit gemeinsamem Zustand oder Verhalten haben. Abstrakte Klassen können Instanzvariablen, Konstruktoren und eine Mischung aus abstrakten und konkreten Methoden enthalten:

public abstract class Animal {
    protected String name;  // gemeinsamer Zustand
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void sleep() {  // gemeinsames Verhalten
        System.out.println(name + " is sleeping");
    }
    
    public abstract void makeSound();  // muss implementiert werden
}

Verwende eine Schnittstelle, wenn du eine Fähigkeit definieren möchtest, die nicht verwandte classes gemeinsam haben can. Schnittstellen konzentrieren sich darauf, was ein Objekt tun can, nicht darauf, was es ist:

public interface Flyable {
    void fly();
}

// Unverwandte Klassen können diese Fähigkeit teilen
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }

Hier ist ein schneller Vergleich:

FunktionAbstrakte KlasseSchnittstelle
InstanzvariablenJaNur Konstanten
KonstruktorenJaNein
MehrfachvererbungNein (einfaches extends)Ja (mehrere implements)
ZugriffsmodifikatorenBeliebigeNur public (für abstrakte Methoden)

Eine praktische Richtlinie: Wenn du eine abstrakte Klasse mit ausschließlich abstrakten Methoden und ohne Zustand erstellst, ist eine Schnittstelle wahrscheinlich die bessere Wahl.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Fahrzeugsystem, das veranschaulicht, wann abstrakte Klassen und wann Schnittstellen verwendet werden. Du modellierst Fahrzeuge, die gemeinsamen Zustand und gemeinsames Verhalten über eine abstrakte Klasse teilen, während optionale Fähigkeiten über Schnittstellen hinzugefügt werden.

Du wirst deinen Code auf fünf Dateien verteilen:

  • Vehicle.java: Erstelle eine abstrakte Klasse, die als Grundlage für alle Fahrzeuge dient. Jedes Fahrzeug hat ein Feld brand (String) und ein Feld year (int). Füge einen Konstruktor hinzu, der beide Felder initialisiert, sowie Getter-Methoden für jedes Feld und eine abstrakte Methode startEngine(), die einen String zurückgibt. Füge außerdem eine konkrete Methode getInfo() hinzu, die Folgendes zurückgibt: [brand] ([year]). Dies ist ein perfekter Anwendungsfall für eine abstrakte Klasse: Fahrzeuge teilen sich Zustand (brand, year) und bestimmtes Verhalten (getInfo), aber jedes Fahrzeug startet seinen Motor auf andere Weise.
  • Convertible.java: Definiere eine Schnittstelle für Fahrzeuge, die ihr Dach öffnen und schließen können. Diese Fähigkeit hängt nicht davon ab, was ein Fahrzeug ist: Es geht um etwas, das bestimmte Fahrzeuge tun können. Deklariere zwei Methoden: openRoof() und closeRoof(), die beide einen String zurückgeben.
  • Car.java: Erstelle eine Klasse, die Vehicle erweitert und Convertible implementiert. Ein Car hat ein zusätzliches Feld numDoors (int). Verwende super, um die geerbten Felder zu initialisieren. Implementiere startEngine() so, dass [brand] car engine started zurückgegeben wird. Implementiere openRoof() so, dass [brand] roof opening zurückgegeben wird, und closeRoof() so, dass [brand] roof closing zurückgegeben wird.
  • Motorcycle.java: Erstelle eine Klasse, die Vehicle erweitert, aber nicht Convertible implementiert: Motorräder haben kein Dach! Ein Motorcycle hat ein Feld hasSidecar (boolean). Implementiere startEngine() so, dass [brand] motorcycle engine roaring zurückgegeben wird.
  • Main.java: Führe alles zusammen, um den Unterschied zwischen abstrakten Klassen und Schnittstellen zu veranschaulichen. Du erhältst vier Eingaben: eine Automarke, ein Autojahr, eine Motorradmarke und ein Motorradjahr.

    Erstelle ein Car (mit 4 Türen) und ein Motorcycle (ohne Beiwagen). Zeige zuerst das gemeinsame Verhalten der abstrakten Klasse, indem du getInfo() für beide Fahrzeuge ausgibst. Beide erben diese Methode von Vehicle. Gib anschließend das Ergebnis von startEngine() für jedes Fahrzeug aus: Beachte, wie jeder Fahrzeugtyp dies unterschiedlich implementiert.

    Zeige schließlich die Fähigkeit der Schnittstelle: Da nur das Car Convertible implementiert, rufe nur für das Auto openRoof() auf und gib das Ergebnis aus, gefolgt von closeRoof().

Du erhältst vier Eingaben: Automarke (String), Autojahr (int), Motorradmarke (String) und Motorradjahr (int).

Deine Ausgabe sollte insgesamt sechs Zeilen enthalten. Beachte, wie beide Fahrzeuge den Zustand der abstrakten Klasse und deren Methode getInfo() gemeinsam nutzen, aber nur das Car die Fähigkeit zum Öffnen und Schließen des Dachs besitzt. Dies veranschaulicht, wann welcher Ansatz verwendet werden sollte!

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Eingaben lesen
        String carBrand = scanner.nextLine();
        int carYear = scanner.nextInt();
        scanner.nextLine(); // Zeilenumbruch konsumieren
        String motorcycleBrand = scanner.nextLine();
        int motorcycleYear = scanner.nextInt();
        
        // TODO: Erstelle ein Car mit 4 Türen
        
        // TODO: Erstelle ein Motorcycle ohne Beiwagen (false)
        
        // TODO: Gib getInfo() für beide Fahrzeuge aus (demonstriert gemeinsames Verhalten der abstrakten Klasse)
        
        // TODO: Gib startEngine() für beide Fahrzeuge aus (demonstriert unterschiedliche Implementierungen)
        
        // TODO: Gib openRoof() und closeRoof() nur für das Auto aus (demonstriert Interface-Fähigkeit)
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Java-Compiler