Menu
Coddy logo textTech

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ę – automatyczne

Podczas 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 Dog

Rzutowanie 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ół.

challenge icon

Wyzwanie

Łatwy

Zbudujmy 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 pole title (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 pole artist (String). Użyj super, aby zainicjalizować klasę nadrzędną. Nadpisz play(), 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ą pole episode (int). Nadpisz play(), 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
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Java online