Klasy i metody abstrakcyjne
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 32 z 87.
Czasami chcesz zdefiniować klasę, która służy jako szablon, ale nigdy nie powinna być bezpośrednio instancjonowana. Na przykład ogólna klasa Shape ma sens jako klasa nadrzędna, ale jak miałby wyglądać „kształt” bez konkretnej formy? Właśnie w takich sytuacjach przydają się klasy abstrakcyjne.
Klasa abstrakcyjna jest deklarowana za pomocą słowa kluczowego abstract i nie można jej tworzyć jako instancji. Może zawierać zarówno zwykłe metody z implementacją, jak i metody abstrakcyjne, które nie mają treści:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Metoda abstrakcyjna – bez implementacji
public abstract double getArea();
// Zwykła metoda – ma implementację
public String getColor() {
return color;
}
}Metody abstrakcyjne deklarują co podklasa musi robić, ale nie jak. Każda nieabstrakcyjna klasa rozszerzająca klasę abstrakcyjną musi dostarczyć implementacje wszystkich metod abstrakcyjnych:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Nadal możesz używać klas abstrakcyjnych jako typów referencyjnych, co umożliwia polimorfizm:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Wywołuje implementację klasy CircleKlasy abstrakcyjne są idealne, gdy podklasy współdzielą wspólny kod, ale każda z nich musi implementować określone zachowania w inny sposób. Wymuszają przestrzeganie kontraktu, jednocześnie umożliwiając ponowne wykorzystanie kodu.
Wyzwanie
ŁatwyZbudujmy system urządzeń, który pokazuje możliwości klas abstrakcyjnych. Utworzysz bazową klasę Appliance, która określa, co musi robić każde urządzenie, pozostawiając konkretnym typom urządzeń decyzję, jak dokładnie to robią.
Rozmieścisz kod w czterech plikach:
Appliance.java: Utwórz klasę abstrakcyjną, która będzie wzorcem dla wszystkich urządzeń. Każde urządzenie ma polebrand(String) i polewattage(int). Dodaj konstruktor inicjalizujący oba pola, metody pobierające wartość każdego z nich oraz zwykłą metodęgetInfo(), która zwraca:[brand] - [wattage]W. Zdefiniuj metodę abstrakcyjnąoperate(), którą muszą implementować podklasy — określa ona, jak każde urządzenie wykonuje swoją główną funkcję.WashingMachine.java: Utwórz konkretną klasę rozszerzającą Appliance. Pralki mają dodatkowe polecapacity(int), określające wielkość wsadu w kg. Użyjsuper, aby obsłużyć inicjalizację klasy nadrzędnej. Zaimplementuj metodęoperate(), aby wyświetlała:[brand] washing machine is washing [capacity]kg of clothesMicrowave.java: Utwórz kolejną konkretną klasę rozszerzającą Appliance. Kuchenki mikrofalowe mają polepower(int), określające procentowy poziom mocy. Zaimplementuj metodęoperate(), aby wyświetlała:[brand] microwave is heating at [power]% powerMain.java: Połącz wszystkie elementy, wykorzystując polimorfizm. Otrzymasz pięć danych wejściowych: nazwę marki, moc w watach, pojemność pralki, nazwę drugiej marki oraz poziom mocy kuchenki mikrofalowej. Utwórz obiekt WashingMachine i obiekt Microwave, a następnie przechowaj je w tablicy odwołań doAppliance. Przejdź pętlą przez tablicę i dla każdego urządzenia wyświetl jego informacje za pomocągetInfo(), a następnie wywołajoperate().
Otrzymasz pięć danych wejściowych w następującej kolejności: pierwsza marka (String), pierwsza moc w watach (int), pojemność w kg (int), druga marka (String) i poziom mocy (int).
Wynik powinien zawierać cztery wiersze — dla każdego urządzenia zobaczysz wiersz z jego informacjami, a następnie opis jego działania. Zwróć uwagę, jak klasa abstrakcyjna pozwala traktować różne urządzenia w jednolity sposób, podczas gdy każde z nich działa na swój własny sposób!
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 brand1 = scanner.nextLine();
int wattage1 = scanner.nextInt();
int capacity = scanner.nextInt();
scanner.nextLine(); // pomiń znak nowej linii
String brand2 = scanner.nextLine();
int power = scanner.nextInt();
// TODO: Utwórz obiekt WashingMachine z brand1, wattage1 i capacity
// TODO: Utwórz obiekt Microwave z brand2, wattage1 (lub odpowiednią mocą) i power
// TODO: Utwórz tablicę referencji do Appliance i umieść w niej oba obiekty
// TODO: Przejdź przez tablicę i dla każdego urządzenia:
// - Wypisz jego informacje za pomocą getInfo()
// - Wywołaj operate()
}
}
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