Dziedziczenie jedno- i wielopoziomowe
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 25 z 87.
Do tej pory widzieliśmy klasy bezpośrednio dziedziczące po jednej klasie nadrzędnej. Dziedziczenie może jednak przyjmować różne struktury w zależności od relacji między klasami. Przyjrzyjmy się dwóm głównym wzorcom: dziedziczeniu pojedynczemu i dziedziczeniu wielopoziomowemu.
Dziedziczenie pojedyncze to rodzaj dziedziczenia, którego używaliśmy. Klasa bezpośrednio rozszerza dokładnie jedną klasę nadrzędną:
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }Tutaj zarówno Dog, jak i Cat dziedziczą po Animal, ale nie dziedziczą po sobie nawzajem. Każda klasa potomna ma jedną bezpośrednią klasę nadrzędną.
Dziedziczenie wielopoziomowe tworzy łańcuch, w którym jedna klasa dziedziczy po innej klasie, która z kolei dziedziczy po kolejnej klasie:
public class Animal {
public void eat() {
System.out.println("Eating");
}
}
public class Mammal extends Animal {
public void breathe() {
System.out.println("Breathing");
}
}
public class Dog extends Mammal {
public void bark() {
System.out.println("Barking");
}
}W tym łańcuchu Dog dziedziczy po Mammal, który dziedziczy po Animal. Obiekt Dog ma dostęp do wszystkich metod z całego łańcucha:
Dog dog = new Dog();
dog.eat(); // Z klasy Animal
dog.breathe(); // Z klasy Mammal
dog.bark(); // Z klasy DogPamiętaj, że Object znajduje się na szczycie każdego łańcucha. Nasz Dog ma więc tak naprawdę cztery poziomy: Object -> Animal -> Mammal -> Dog. Podczas tworzenia nowego obiektu wywołania konstruktorów przechodzą przez wszystkie te poziomy.
Wyzwanie
ŁatwyStwórzmy hierarchię pojazdów, która pokazuje zarówno dziedziczenie jednopoziomowe, jak i wielopoziomowe. Utworzysz łańcuch klas, w którym każdy poziom dodaje nowe możliwości, pokazując, jak metody są dziedziczone przez wiele poziomów.
Rozmieścisz swój kod w czterech plikach:
Vehicle.java: Utwórz klasę bazową na szczycie hierarchii. Każdy pojazd powinien mieć:- Prywatne pole przechowujące
brand(String) - Konstruktor przyjmujący markę
- Metodę
getBrand(), która zwraca markę - Metodę
move(), która wyświetla:[brand] is moving
- Prywatne pole przechowujące
LandVehicle.java: Utwórz klasę rozszerzającą Vehicle, reprezentującą środkowy poziom twojego wielopoziomowego łańcucha. Pojazdy lądowe dodają zachowanie specyficzne dla poruszania się po ziemi:- Prywatne pole przechowujące
wheels(int) - Konstruktor przyjmujący markę i liczbę kół, używający
super(brand)dla części klasy nadrzędnej - Metodę
getWheels(), która zwraca liczbę kół - Metodę
honk(), która wyświetla:[brand] honks!
- Prywatne pole przechowujące
Car.java: Utwórz klasę rozszerzającą LandVehicle, uzupełniającą trzy poziomy łańcucha dziedziczenia. Samochody dodają własne specjalistyczne cechy:- Prywatne pole przechowujące
model(String) - Konstruktor przyjmujący markę, liczbę kół i model, używający
super(brand, wheels) - Metodę
getModel(), która zwraca model - Metodę
displayInfo(), która wyświetla:[brand] [model] with [wheels] wheels
- Prywatne pole przechowujące
Main.java: Pokaż, jak obiekt Car ma dostęp do metod ze wszystkich trzech poziomów hierarchii. Otrzymasz trzy dane wejściowe: markę (String), liczbę kół (int) i model (String). Utwórz obiekt Car i wywołaj kolejno te metody:move()— odziedziczona z Vehicle (dziadka)honk()— odziedziczona z LandVehicle (rodzica)displayInfo()— zdefiniowana w samej klasie Car
Otrzymasz trzy dane wejściowe: nazwę marki, liczbę kół i nazwę modelu.
Wynik powinien zawierać trzy wiersze pokazujące, jak obiekt Car może korzystać z metod z każdego poziomu swojego łańcucha dziedziczenia — od najwyższego poziomu Vehicle aż po własną klasę!
Spróbuj swoich sił
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Odczytaj dane wejściowe
String brand = scanner.nextLine();
int wheels = scanner.nextInt();
scanner.nextLine(); // odczytaj znak nowej linii
String model = scanner.nextLine();
// TODO: Utwórz obiekt Car z wartościami wejściowymi
// TODO: Wywołaj move() — odziedziczoną po Vehicle (klasie nadrzędnej klasy nadrzędnej)
// TODO: Wywołaj honk() — odziedziczoną po LandVehicle (klasie nadrzędnej)
// TODO: Wywołaj displayInfo() — zdefiniowaną w samej klasie Car
}
}
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