Upcasting und Downcasting
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 30 von 87.
In der vorherigen Lektion haben Sie gesehen, wie eine Variable vom Typ der Elternklasse ein Objekt der Kindklasse halten kann: Animal myPet = new Dog(). Diese Zuweisung wird Upcasting genannt, und sie erfolgt automatisch, da ein Dog immer ein Animal ist.
Upcasting bewegt sich in der Vererbungshierarchie nach oben. Es ist implizit und immer sicher:
Dog dog = new Dog();
Animal animal = dog; // Upcasting - automatischBeim Upcasting können Sie nur auf Methoden zugreifen, die in der Elternklasse definiert sind. Die kindspezifischen Methoden werden ausgeblendet, obwohl das Objekt im Hintergrund immer noch ein Dog ist.
Downcasting geht in die entgegengesetzte Richtung und wandelt eine Elternreferenz wieder in einen Kindtyp um. Dies erfordert einen expliziten Cast, da es nicht immer sicher ist:
Animal animal = new Dog(); // Upcasting
Dog dog = (Dog) animal; // Downcasting - expliziter Cast erforderlich
dog.bark(); // Jetzt können wir auf Dog-Methoden zugreifenDowncasting ist riskant. Wenn das Objekt nicht tatsächlich der Typ ist, in den Sie casten, wirft Java zur Laufzeit eine ClassCastException:
Animal animal = new Cat();
Dog dog = (Dog) animal; // Kompiliert, stürzt aber zur Laufzeit ab!Der Compiler kann diesen Fehler nicht abfangen, da er nur die deklarierten Typen sieht. Der tatsächliche Objekttyp ist erst bekannt, wenn das Programm ausgeführt wird. In der nächsten Lektion lernen Sie, wie Sie den Typ eines Objekts sicher prüfen, bevor Sie ein Downcasting durchführen.
Aufgabe
EinfachLassen Sie uns ein Mediaplayer-System bauen, das sowohl Upcasting als auch Downcasting in Aktion demonstriert. Sie werden eine Hierarchie von Medientypen erstellen und das Konvertieren zwischen Eltern- und Kind-Referenzen üben.
Sie werden Ihren Code über vier Dateien organisieren:
Media.java: Erstellen Sie die Basisklasse, die alle Medientypen gemeinsam haben. Jedes Medienelement hat eintitle-Feld (String). Fügen Sie einen Konstruktor zu dessen Initialisierung, eine Getter-MethodegetTitle()und eine Methodeplay()hinzu, die Folgendes ausgibt:Playing: [title]Song.java: Erstellen Sie eine Klasse, die Media erweitert. Songs haben ein zusätzlichesartist-Feld (String). Verwenden Siesuperfür die Initialisierung der Elternklasse. Überschreiben Sieplay(), um Folgendes auszugeben:Playing song: [title] by [artist]. Fügen Sie eine MethodeshowArtist()hinzu, die Folgendes ausgibt:Artist: [artist]Podcast.java: Erstellen Sie eine weitere Klasse, die Media erweitert. Podcasts haben einepisode-Feld (int). Überschreiben Sieplay(), um Folgendes auszugeben:Playing podcast: [title] - Episode [episode]. Fügen Sie eine MethodeshowEpisode()hinzu, die Folgendes ausgibt:Episode: [episode]Main.java: Demonstrieren Sie Upcasting und Downcasting mit Ihren Medientypen. Sie erhalten vier Eingaben: einen Songtitel, einen Künstlernamen, einen Podcasttitel und eine Episodennummer.Erstellen Sie zuerst einen Song und führen Sie ein Upcasting auf eine Media-Referenz durch. Rufen Sie
play()auf dieser Referenz auf, um die Laufzeit-Polymorphie in Aktion zu sehen.Führen Sie als Nächstes ein Downcasting dieser Media-Referenz zurück zu einem Song durch und rufen Sie
showArtist()auf, um auf die kindspezifische Methode zuzugreifen.Erstellen Sie dann einen Podcast und führen Sie ein Upcasting auf eine Media-Referenz durch. Rufen Sie
play()auf dieser Referenz auf.Führen Sie schließlich ein Downcasting dieser Media-Referenz zurück zu einem Podcast durch und rufen Sie
showEpisode()auf.
Sie erhalten vier Eingaben: den Songtitel (String), den Künstlernamen (String), den Podcasttitel (String) und die Episodennummer (int).
Ihre Ausgabe sollte vier Zeilen zeigen - zwei für den Song (seine Play-Ausgabe und Künstler-Info) und zwei für den Podcast (seine Play-Ausgabe und Episoden-Info). Beachten Sie, wie Upcasting es Ihnen ermöglicht, verschiedene Medientypen einheitlich zu behandeln, während Downcasting Ihnen den Zugriff auf ihre einzigartigen Funktionen ermöglicht!
Spickzettel
In Java bewegt sich Upcasting in der Vererbungshierarchie nach oben und erfolgt automatisch. Ein Kind-Objekt kann einer Variable vom Typ der Elternklasse zugewiesen werden:
Dog dog = new Dog();
Animal animal = dog; // Upcasting - automatischBeim Upcasting können Sie nur auf Methoden zugreifen, die in der Elternklasse definiert sind, obwohl das Objekt im Hintergrund immer noch vom Typ der Kindklasse ist.
Downcasting konvertiert eine Referenz der Elternklasse zurück in einen Typ der Kindklasse. Dies erfordert einen expliziten Cast:
Animal animal = new Dog(); // Upcasting
Dog dog = (Dog) animal; // Downcasting - expliziter Cast erforderlich
dog.bark(); // Jetzt können wir auf Dog-Methoden zugreifenDowncasting ist riskant. Wenn das Objekt nicht tatsächlich von dem Typ ist, in den Sie casten, wirft Java zur Laufzeit eine ClassCastException:
Animal animal = new Cat();
Dog dog = (Dog) animal; // Kompiliert, stürzt aber zur Laufzeit ab!Der Compiler kann diesen Fehler nicht abfangen, da er nur die deklarierten Typen sieht. Der tatsächliche Objekttyp ist erst bekannt, wenn das Programm ausgeführt wird.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Eingaben lesen
String songTitle = scanner.nextLine();
String artistName = scanner.nextLine();
String podcastTitle = scanner.nextLine();
int episodeNumber = scanner.nextInt();
// TODO: Erstelle einen Song und führe einen Upcast auf eine Media-Referenz durch
// TODO: Rufe play() auf der Media-Referenz auf (demonstriert Polymorphismus)
// TODO: Führe einen Downcast der Media-Referenz zurück zu Song durch
// TODO: Rufe showArtist() auf der Song-Referenz auf
// TODO: Erstelle einen Podcast und führe einen Upcast auf eine Media-Referenz durch
// TODO: Rufe play() auf der Media-Referenz auf
// TODO: Führe einen Downcast der Media-Referenz zurück zu Podcast durch
// TODO: Rufe showEpisode() auf der Podcast-Referenz 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