Menu
Coddy logo textTech

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);
challenge icon

Wyzwanie

Łatwy

Stwó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 klasa GiftBox<T> powinna mieć prywatne pole item typu T oraz prywatne pole wrapped (boolean), którego początkową wartością jest false. 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 klasa Registry<K, V> powinna mieć prywatne pola recipient typu K i gift typu V. Dodaj konstruktor przyjmujący obie wartości, metody pobierające getRecipient() i getGift() 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ą metody wrap(), 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()
    }
}
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