Rzutowanie w górę i w dół
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 30 z 87.
W poprzedniej lekcji zobaczyłeś, jak zmienna typu nadrzędnego może przechowywać obiekt typu potomnego: Animal myPet = new Dog(). To przypisanie nazywa się rzutowaniem w górę i odbywa się automatycznie, ponieważ Dog zawsze jest Animal.
Rzutowanie w górę przesuwa w górę hierarchii dziedziczenia. Jest niejawne i zawsze bezpieczne:
Dog dog = new Dog();
Animal animal = dog; // Rzutowanie w górę – automatycznePodczas rzutowania w górę możesz uzyskać dostęp tylko do metod zdefiniowanych w klasie nadrzędnej. Metody właściwe dla klasy potomnej zostają ukryte, mimo że obiekt nadal jest pod spodem obiektem typu Dog.
Rzutowanie w dół przebiega w przeciwnym kierunku — konwertuje referencję do typu nadrzędnego z powrotem na typ potomny. Wymaga jawnego rzutowania, ponieważ nie zawsze jest bezpieczne:
Animal animal = new Dog(); // Rzutowanie w górę hierarchii
Dog dog = (Dog) animal; // Rzutowanie w dół hierarchii — wymagane jawne rzutowanie
dog.bark(); // Teraz możemy korzystać z metod DogRzutowanie w dół jest ryzykowne. Jeśli obiekt nie jest w rzeczywistości typem, na który go rzutujesz, Java zgłasza w czasie wykonywania wyjątek ClassCastException:
Animal animal = new Cat();
Dog dog = (Dog) animal; // Kompiluje się, ale kończy się błędem podczas działania!Kompilator nie może wykryć tego błędu, ponieważ widzi tylko zadeklarowane typy. Rzeczywisty typ obiektu jest znany dopiero podczas działania programu. W następnej lekcji dowiesz się, jak bezpiecznie sprawdzić typ obiektu przed rzutowaniem w dół.
Wyzwanie
ŁatwyZbudujmy system odtwarzacza multimediów, który pokazuje w praktyce zarówno rzutowanie w górę, jak i rzutowanie w dół. Utworzysz hierarchię typów multimediów i przećwiczysz konwersję między referencjami do klas nadrzędnych i podrzędnych.
Rozmieścisz swój kod w czterech plikach:
Media.java: Utwórz klasę bazową wspólną dla wszystkich typów multimediów. Każdy element multimedialny ma poletitle(String). Dodaj konstruktor, który je inicjalizuje, metodę pobierającągetTitle()oraz metodęplay(), która wyświetla:Playing: [title]Song.java: Utwórz klasę rozszerzającą Media. Utwory mają dodatkowe poleartist(String). Użyjsuper, aby zainicjalizować klasę nadrzędną. Nadpiszplay(), aby wyświetlała:Playing song: [title] by [artist]. Dodaj metodęshowArtist(), która wyświetla:Artist: [artist]Podcast.java: Utwórz kolejną klasę rozszerzającą Media. Podcasty mają poleepisode(int). Nadpiszplay(), aby wyświetlała:Playing podcast: [title] - Episode [episode]. Dodaj metodęshowEpisode(), która wyświetla:Episode: [episode]Main.java: Zademonstruj rzutowanie w górę i w dół dla typów multimediów. Otrzymasz cztery dane wejściowe: tytuł utworu, nazwę wykonawcy, tytuł podcastu i numer odcinka.Najpierw utwórz obiekt Song i rzutuj go w górę do referencji Media. Wywołaj
play()na tej referencji, aby zobaczyć polimorfizm w czasie wykonywania.Następnie rzutuj tę referencję Media w dół z powrotem do Song i wywołaj
showArtist(), aby uzyskać dostęp do metody właściwej dla klasy podrzędnej.Potem utwórz obiekt Podcast i rzutuj go w górę do referencji Media. Wywołaj
play()na tej referencji.Na koniec rzutuj tę referencję Media w dół z powrotem do Podcast i wywołaj
showEpisode().
Otrzymasz cztery dane wejściowe: tytuł utworu (String), nazwę wykonawcy (String), tytuł podcastu (String) i numer odcinka (int).
Wynik powinien składać się z czterech wierszy — dwóch dotyczących utworu (wynik jego odtwarzania i informacje o wykonawcy) oraz dwóch dotyczących podcastu (wynik jego odtwarzania i informacje o odcinku). Zwróć uwagę, że rzutowanie w górę pozwala traktować różne typy multimediów w jednolity sposób, a rzutowanie w dół umożliwia dostęp do ich unikalnych cech!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Wczytaj dane wejściowe
String songTitle = scanner.nextLine();
String artistName = scanner.nextLine();
String podcastTitle = scanner.nextLine();
int episodeNumber = scanner.nextInt();
// TODO: Utwórz obiekt Song i rzutuj go w górę na referencję typu Media
// TODO: Wywołaj play() przez referencję typu Media (demonstruje polimorfizm)
// TODO: Rzutuj referencję typu Media z powrotem w dół na typ Song
// TODO: Wywołaj showArtist() przez referencję typu Song
// TODO: Utwórz obiekt Podcast i rzutuj go w górę na referencję typu Media
// TODO: Wywołaj play() przez referencję typu Media
// TODO: Rzutuj referencję typu Media z powrotem w dół na typ Podcast
// TODO: Wywołaj showEpisode() przez referencję typu Podcast
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online