Klasy generyczne
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 54 z 87.
Skoro już wiesz, dlaczego typy generyczne są przydatne, utwórzmy własną klasę generyczną. Klasa generyczna deklaruje jeden lub więcej parametrów typu w nawiasach ostrych po nazwie klasy. Można ich następnie używać w całej klasie.
class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}T to parametr typu: symbol zastępczy, który jest zastępowany rzeczywistym typem podczas tworzenia instancji. Możesz użyć dowolnej nazwy, ale standardowo stosuje się pojedyncze wielkie litery: T oznacza typ (Type), E element (Element), K klucz (Key), a V wartość (Value).
Podczas tworzenia instancji klasy generycznej określasz właściwy typ w nawiasach ostrych:
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get(); // Nie jest potrzebne rzutowanie
Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer num = intBox.get();Zwróć uwagę na <> (operator diamentowy) po prawej stronie: Java wywnioskuje typ z deklaracji. Możesz też użyć wielu parametrów typów w klasach, które muszą działać z więcej niż jednym typem:
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
Pair<String, Integer> pair = new Pair<>("age", 25);Wyzwanie
ŁatwyStwórzmy system rejestru prezentów, który pokazuje możliwości klas generycznych. Utworzysz elastyczny system przechowywania, który może przechowywać dowolny rodzaj prezentu, a także rejestr, który łączy nazwy prezentów z ich szczegółami za pomocą wielu parametrów typów.
Rozmieścisz swój kod w trzech plikach:
GiftBox.java: Utwórz klasę generyczną, która może opakować dowolny rodzaj prezentu. Twoja klasaGiftBox<T>powinna mieć prywatne poleitemtypuToraz prywatne polewrapped(boolean), którego początkową wartością jestfalse. Dodaj konstruktor przyjmujący element, metodęgetItem(), która zwraca element, metodęwrap(), która ustawia wrapped na true, oraz metodęisWrapped(), która zwraca stan opakowania. Dodaj metodęgetStatus(), która zwraca[item] (wrapped)lub[item] (unwrapped)w zależności od stanu opakowania.Registry.java: Utwórz klasę generyczną z dwoma parametrami typów, która łączy odbiorcę z jego prezentem. Twoja klasaRegistry<K, V>powinna mieć prywatne polarecipienttypuKigifttypuV. Dodaj konstruktor przyjmujący obie wartości, metody pobierającegetRecipient()igetGift()oraz metodęgetEntry(), która zwraca:[recipient] -> [gift]Main.java: Ożyw swój rejestr prezentów! Otrzymasz trzy dane wejściowe: imię odbiorcy (String), opis prezentu (String) i wartość prezentu (liczbę całkowitą reprezentującą dolary).Najpierw utwórz obiekt
GiftBox<String>zawierający opis prezentu. Opakuj go za pomocą metodywrap(), a następnie wyświetl jego stan.Następnie utwórz obiekt
GiftBox<Integer>zawierający wartość prezentu (reprezentującą kwotę na karcie podarunkowej). Nie opakowuj go: wyświetl jego stan, aby pokazać, że nie jest opakowany.Na koniec utwórz obiekt
Registry<String, String>, łączący imię odbiorcy z opisem prezentu, i wyświetl wpis w rejestrze.
Otrzymasz trzy dane wejściowe w następującej kolejności: imię odbiorcy, opis prezentu i wartość prezentu (jako liczbę całkowitą).
Zwróć uwagę, że ta sama klasa GiftBox działa bez problemu zarówno z typem String, jak i Integer: na tym polega piękno typów generycznych! Klasa Registry pokazuje natomiast, jak wiele parametrów typów pozwala tworzyć elastyczne powiązania między dowolnymi dwoma typami.
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 recipientName = scanner.nextLine();
String giftDescription = scanner.nextLine();
int giftValue = scanner.nextInt();
// TODO: Utwórz GiftBox<String> zawierający opis prezentu
// TODO: Zapakuj go za pomocą metody wrap()
// TODO: Wyświetl jego status za pomocą getStatus()
// TODO: Utwórz GiftBox<Integer> zawierający wartość prezentu
// TODO: Nie pakuj tego prezentu — wyświetl jego status (powinien wskazywać, że nie jest zapakowany)
// TODO: Utwórz Registry<String, String> łączący odbiorcę z opisem prezentu
// TODO: Wyświetl wpis rejestru za pomocą getEntry()
}
}
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