Menu
Coddy logo textTech

Przesłanianie metod (w czasie wykonywania)

Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 29 z 87.

Podczas gdy przeciążanie metod jest rozstrzygane w czasie kompilacji, przesłanianie metod demonstruje polimorfizm czasu wykonania. W tym przypadku Java decyduje, którą metodę wykonać, gdy program jest uruchomiony, na podstawie rzeczywistego typu obiektu, a nie zadeklarowanego typu zmiennej.

Dowiedziałeś się o przesłanianiu metod w rozdziale Inheritance. O tym, że jest polimorficzne, decyduje sposób, w jaki Java obsługuje je, gdy referencja do klasy nadrzędnej wskazuje na obiekt klasy potomnej:

public class Animal {
    public void speak() {
        System.out.println("Some sound");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Bark!");
    }
}

public class Cat extends Animal {
    @Override
    public void speak() {
        System.out.println("Meow!");
    }
}

Teraz zobacz, co się dzieje, gdy używamy odwołań do typu nadrzędnego:

Animal myPet = new Dog();
myPet.speak();  // Wynik: Bark!

myPet = new Cat();
myPet.speak();  // Wynik: Meow!

Mimo że myPet jest zadeklarowane jako Animal, Java wywołuje nadpisaną metodę na podstawie rzeczywistego typu obiektu w czasie wykonywania. Nazywa się to dynamicznym wiązaniem metod. JVM sprawdza, czym naprawdę jest obiekt, a nie co mówi zmienna.

Umożliwia to tworzenie zaawansowanych wzorców, takich jak jednolite przetwarzanie różnych obiektów:

Animal[] pets = {new Dog(), new Cat(), new Dog()};
for (Animal pet : pets) {
    pet.speak();  // Każdy wywołuje własną wersję
}

Polimorfizm czasu wykonania pozwala pisać elastyczny kod, który działa z typami nadrzędnymi, a jednocześnie automatycznie korzysta z właściwego zachowania typów potomnych.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system powiadomień, który pokazuje polimorfizm czasu wykonania w praktyce. Utworzysz hierarchię typów powiadomień, w której to samo wywołanie metody daje różne wyniki, zależnie od rzeczywistego typu obiektu w czasie wykonania.

Rozmieścisz kod w czterech plikach:

  • Notification.java: Utwórz klasę bazową wspólną dla wszystkich powiadomień. Każde powiadomienie ma pole recipient (String). Dodaj konstruktor, który je inicjalizuje, metodę pobierającą oraz metodę send(), która wyświetla: Sending notification to [recipient]
  • EmailNotification.java: Utwórz klasę rozszerzającą Notification. Powiadomienia e-mail dodają pole subject. Użyj super do inicjalizacji klasy nadrzędnej. Przesłoń metodę send(), aby wyświetlała: Emailing [recipient]: [subject]
  • SMSNotification.java: Utwórz kolejną klasę rozszerzającą Notification. Powiadomienia SMS dodają pole phoneNumber. Przesłoń metodę send(), aby wyświetlała: Texting [phoneNumber] for [recipient]
  • Main.java: Tutaj polimorfizm czasu wykonania pokazuje swoje możliwości! Otrzymasz trzy dane wejściowe: nazwę odbiorcy, temat wiadomości e-mail i numer telefonu. Utwórz tablicę odwołań typu Notification zawierającą trzy obiekty w następującej kolejności: podstawowy obiekt Notification, EmailNotification i SMSNotification (wszystkie z tym samym odbiorcą). Następnie przejdź pętlą przez tablicę i wywołaj send() dla każdego elementu. Zobacz, jak Java automatycznie wywołuje właściwą przesłoniętą wersję metody, zależnie od rzeczywistego typu każdego obiektu!

Otrzymasz trzy dane wejściowe: nazwę odbiorcy (String), temat wiadomości e-mail (String) i numer telefonu (String).

Wynik powinien zawierać trzy wiersze — każde wywołanie send() daje inny wynik, mimo że wywołujesz tę samą metodę na odwołaniach typu Notification. Właśnie tak działa dynamiczne wiązanie metod!

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 recipient = scanner.nextLine();
        String subject = scanner.nextLine();
        String phoneNumber = scanner.nextLine();
        
        // TODO: Utwórz tablicę referencji do obiektów Notification zawierającą 3 elementy
        // Tablica powinna zawierać (w tej kolejności):
        // 1. Obiekt bazowej klasy Notification
        // 2. Obiekt klasy EmailNotification
        // 3. Obiekt klasy SMSNotification
        // Wszystkie z tym samym odbiorcą
        
        // TODO: Przejdź przez tablicę i wywołaj send() dla każdego elementu
        // To ilustruje polimorfizm dynamiczny!
    }
}
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