Warum keine Mehrfachvererbung von Klassen
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 26 von 87.
Java verhindert absichtlich, dass eine Klasse mehr als eine Klasse erweitert. Diese Einschränkung existiert aufgrund eines Problems, das als das Diamond-Problem bekannt ist.
Stellen Sie sich vor, Java würde Mehrfachvererbung erlauben. Betrachten Sie dieses hypothetische Szenario:
// Dieser Code ist in Java NICHT gültig
public class A {
public void greet() {
System.out.println("Hello from A");
}
}
public class B extends A {
@Override
public void greet() {
System.out.println("Hello from B");
}
}
public class C extends A {
@Override
public void greet() {
System.out.println("Hello from C");
}
}
// In Java NICHT erlaubt!
public class D extends B, C { }Wenn Sie greet() für ein D-Objekt aufrufen würden, welche Version sollte ausgeführt werden? Die von B oder C? Diese Mehrdeutigkeit ist das Diamond-Problem, benannt nach der Rautenform, die durch das Vererbungsdiagramm entsteht.
Javas Lösung ist einfach: Es ist nur die Einfachvererbung von Klassen zulässig. Java bietet jedoch eine Alternative. Eine Klasse kann mehrere Interfaces implementieren, worüber Sie in einem der nächsten Kapitel mehr erfahren werden.
Interfaces lösen das Diamond-Problem auf andere Weise und bieten Ihnen Flexibilität ohne die Mehrdeutigkeit.
// Dies IST in Java gültig
public class Dog extends Animal implements Runnable, Comparable<Dog> {
// Kann mehrere Interfaces implementieren
}Diese Designentscheidung hält Javas Vererbungsmodell sauber und vorhersehbar, während sie gleichzeitig eine leistungsstarke Wiederverwendung von Code durch Interfaces ermöglicht.
Aufgabe
EinfachLassen Sie uns ein Musik-Player-System bauen, das die Regel der einfachen Vererbung in Java demonstriert und zeigt, wie Sie innerhalb dieser Einschränkung dennoch flexible Designs erreichen können.
Stellen Sie sich vor, Sie möchten einen Smart Speaker erstellen, der Funktionen eines Musik-Players und eines Sprachassistenten kombiniert. Da Java das Erweitern mehrerer Klassen nicht erlaubt, müssen Sie Ihre Hierarchie sorgfältig unter Verwendung der einfachen Vererbung entwerfen.
Sie werden vier Dateien erstellen, um Ihren Code zu organisieren:
AudioDevice.java: Erstellen Sie die Basisklasse, die alle audio-abspielenden Geräte gemeinsam haben. Sie sollte Folgendes enthalten:- Ein privates Feld für
deviceName(String) - Einen Konstruktor, der den Gerätenamen akzeptiert
- Eine Methode
getDeviceName(), die den Namen zurückgibt - Eine Methode
playSound(), die Folgendes ausgibt:[deviceName]: Playing audio
- Ein privates Feld für
MusicPlayer.java: Erstellen Sie eine Klasse, die AudioDevice erweitert und musikspezifische Funktionen hinzufügt:- Ein privates Feld für
currentSong(String) - Einen Konstruktor, der den Gerätenamen entgegennimmt und
super(deviceName)verwendet - Eine Methode
setSong(String song), die das aktuelle Lied festlegt - Überschreiben Sie
playSound(), um Folgendes auszugeben:[deviceName]: Now playing - [currentSong]
- Ein privates Feld für
SmartSpeaker.java: Erstellen Sie eine Klasse, die MusicPlayer erweitert (nicht sowohl MusicPlayer als auch eine VoiceAssistant-Klasse – das wäre Mehrfachvererbung!). Der Smart Speaker baut auf dem Musik-Player auf, indem er Sprachfunktionen hinzufügt:- Ein privates Feld für
assistantName(String) - Einen Konstruktor, der den Gerätenamen und den Namen des Assistenten entgegennimmt und
super(deviceName)verwendet - Eine Methode
voiceCommand(String command), die Folgendes ausgibt:[assistantName]: Processing "[command]" - Eine Methode
getFullInfo(), die Folgendes ausgibt:[deviceName] with [assistantName] assistant
- Ein privates Feld für
Main.java: Demonstrieren Sie Ihre mehrstufige Vererbungskette. Sie erhalten drei Eingaben: einen Gerätenamen (String), einen Namen für den Assistenten (String) und einen Namen für ein Lied (String). Erstellen Sie einen SmartSpeaker, legen Sie ein Lied fest und rufen Sie dann diese Methoden in der folgenden Reihenfolge auf:getFullInfo()playSound()voiceCommand("skip to next")
Sie erhalten drei Eingaben: den Gerätenamen, den Namen des Assistenten und den Namen des Liedes.
Beachten Sie, wie der SmartSpeaker Musikfunktionen erhält, indem er MusicPlayer in einer Kette erweitert (AudioDevice -> MusicPlayer -> SmartSpeaker), anstatt zu versuchen, mehrere nicht verwandte Klassen zu erweitern. Dies ist Javas Ansatz, um Vererbung sauber und eindeutig zu halten!
Spickzettel
Java erlaubt nur Einfachvererbung - eine Klasse kann nur eine andere Klasse erweitern. Dies verhindert das Diamond-Problem, bei dem Unklarheiten entstehen, wenn eine Klasse dieselbe Methode von mehreren Elternklassen erben könnte.
// NICHT erlaubt in Java - Mehrfachvererbung
public class D extends B, C { } // FEHLER!Java erlaubt es einer Klasse jedoch, als Alternative mehrere Interfaces zu implementieren:
// Gültig in Java
public class Dog extends Animal implements Runnable, Comparable<Dog> {
// Kann eine Klasse erweitern und mehrere Interfaces implementieren
}Java unterstützt mehrstufige Vererbung - das Erstellen von Vererbungsketten:
public class AudioDevice { }
public class MusicPlayer extends AudioDevice { }
public class SmartSpeaker extends MusicPlayer { }
// SmartSpeaker erbt sowohl von MusicPlayer als auch von AudioDeviceProbier es selbst
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Eingaben lesen
String deviceName = scanner.nextLine();
String assistantName = scanner.nextLine();
String songName = scanner.nextLine();
// TODO: Erstelle einen SmartSpeaker mit deviceName und assistantName
// TODO: Setze den Song mit setSong()
// TODO: Rufe getFullInfo() auf
// TODO: Rufe playSound() auf
// TODO: Rufe voiceCommand("skip to next") auf
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem