Menu
Coddy logo textTech

Обобщенные классы

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 54 из 87.

Теперь, когда вы понимаете, почему дженерики полезны, давайте создадим собственный обобщённый класс. Обобщённый класс объявляет один или несколько параметров типов в угловых скобках после имени класса, которые затем можно использовать во всём классе.

class Box<T> {
    private T content;
    
    public void set(T content) {
        this.content = content;
    }
    
    public T get() {
        return content;
    }
}

T — это параметр типа: заполнитель, который заменяется фактическим типом при создании экземпляра. Можно использовать любое имя, но обычно используют одиночные заглавные буквы: T для Type, E для Element, K для Key, V для Value.

При создании экземпляра обобщённого класса укажите фактический тип в угловых скобках:

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get();  // Приведение типов не требуется

Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer num = intBox.get();

Обратите внимание на <> (ромбовидный оператор) с правой стороны: Java выводит тип из объявления. Вы также можете использовать несколько параметров типа для классов, которым необходимо работать более чем с одним типом:

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

Задание

Легко

Давайте создадим систему реестра подарков, демонстрирующую возможности обобщённых классов. Вы создадите гибкую систему хранения, способную содержать любой тип подарка, а также реестр, который сопоставляет названия подарков с их описаниями, используя несколько параметров типа.

Вы распределите код по трём файлам:

  • GiftBox.java: Create обобщённый class, который может упаковывать любой тип подарка. Ваш GiftBox<T> должен иметь private field item типа T и private field wrapped (boolean), изначально имеющий значение false. Добавьте constructor, который accepts item, метод getItem(), возвращающий item, метод wrap(), устанавливающий wrapped в значение true, и метод isWrapped(), возвращающий статус wrapped. Добавьте метод getStatus(), который возвращает либо [item] (wrapped), либо [item] (unwrapped) в зависимости от состояния wrapped.
  • Registry.java: Create обобщённый class с двумя параметрами типа, который сопоставляет получателя с его подарком. Ваш Registry<K, V> должен иметь private fields recipient типа K и gift типа V. Добавьте constructor, который accepts both значения, getter methods getRecipient() и getGift(), а также метод getEntry(), который возвращает: [recipient] -> [gift]
  • Main.java: Оживите свой реестр подарков! Вы получите три входных значения: имя получателя (String), описание подарка (String) и стоимость подарка (целое число, представляющее сумму в долларах).

    Сначала создайте GiftBox<String>, содержащий описание подарка. Упакуйте его с помощью метода wrap(), затем выведите его статус.

    Затем создайте GiftBox<Integer>, содержащий стоимость подарка (представляющую сумму подарочной карты). Не упаковывайте этот объект: выведите его статус, чтобы показать, что он не упакован.

    Наконец, создайте Registry<String, String>, сопоставляющий имя получателя с описанием подарка, и выведите запись реестра.

Вы получите три входных значения в следующем порядке: имя получателя, описание подарка и стоимость подарка (в виде целого числа).

Обратите внимание, как один и тот же GiftBox без проблем работает как с типом String, так и с типом Integer: в этом и заключается преимущество обобщений! А class Registry демонстрирует, как несколько параметров типа позволяют создавать гибкие пары между любыми двумя типами.

Попробуйте сами

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Считать входные данные
        String recipientName = scanner.nextLine();
        String giftDescription = scanner.nextLine();
        int giftValue = scanner.nextInt();
        
        // TODO: Создайте GiftBox&lt;String&gt;, содержащий описание подарка
        // TODO: Оберните его с помощью метода wrap()
        // TODO: Выведите его статус с помощью getStatus()
        
        // TODO: Создайте GiftBox&lt;Integer&gt;, содержащий стоимость подарка
        // TODO: Не оборачивайте этот — выведите его статус (должен показывать unwrapped)
        
        // TODO: Создайте Registry&lt;String, String&gt;, связывающий получателя с описанием подарка
        // TODO: Выведите запись реестра с помощью getEntry()
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java