Ограниченные параметры типа
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 56 из 87.
До сих пор наши параметры generic-типа могли принимать любой тип. Но что, если нужно их ограничить?
Например, method, вычисляющий сумму чисел, не должен принимать строки. Ограниченные параметры типов позволяют ограничить типы, которые можно использовать с вашими generic.
Используйте ключевое слово extends, чтобы задать верхнюю границу параметра типа:
class NumberBox<T extends Number> {
private T value;
public NumberBox(T value) {
this.value = value;
}
public double getDoubleValue() {
return value.doubleValue(); // Можно вызывать методы Number!
}
}
NumberBox<Integer> intBox = new NumberBox<>(42);
NumberBox<Double> doubleBox = new NumberBox<>(3.14);
// NumberBox<String> strBox = new NumberBox<>("Hi"); // Ошибка компиляции!Ограничение T extends Number означает, что T должен быть Number или любым из его подклассов (Integer, Double и т. д.). Это также позволяет вызывать methods, определённые в Number, для параметра типа.
Вы можете указать multiple ограничений с помощью &. Если одно из ограничений — class, оно должно стоять первым:
class DataProcessor<T extends Number & Comparable<T>> {
public boolean isGreater(T a, T b) {
return a.compareTo(b) > 0;
}
}Здесь T должен расширять Number И реализовывать Comparable. Ограниченные параметры типа также работают с обобщёнными методами:
public static <T extends Comparable<T>> T findMax(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
String result = findMax("apple", "banana"); // Возвращает "banana"Ограниченные параметры типов делают ваши обобщения более мощными, обеспечивая безопасность типов и одновременно предоставляя доступ к определённым методам типа-ограничения.
Задание
ЛегкоДавайте создадим калькулятор статистики, который работает только с числовыми типами! Вы будете использовать bounded type parameters, чтобы гарантировать, что ваш калькулятор может обрабатывать только числа, получая при этом доступ к полезным методам из class Number.
Вы организуете свой код в трёх файлах:
NumberStats.java: Create generic class, вычисляющий статистические показатели для числовых значений. Ваш classNumberStats<T extends Number>должен хранить два private fields типаT:value1иvalue2. Добавьте constructor, который accepts both значения. Добавьте methodgetSum(), возвращающий сумму both значений какdouble(используйте methoddoubleValue(), унаследованный от Number). Также добавьте methodgetAverage(), возвращающий среднее двух значений какdouble.ComparableBox.java: Create generic class с multiple bounds, который может находить larger из двух значений. Ваш classComparableBox<T extends Number & Comparable<T>>должен хранить два private fields типаT:firstиsecond. Добавьте constructor, который accepts both значения. Добавьте methodgetMax(), возвращающий larger значение с использованиемcompareTo(). Также добавьте methodgetMaxAsDouble(), возвращающий larger значение, converted вdouble.Main.java: Воплотите в жизнь свои bounded generics! Вы получите четыре inputs: два integer и два double.Сначала создайте
NumberStats<Integer>с двумя integer значениями. Выведите сумму и среднее:Integer sum: [sum] Integer average: [average]Затем создайте
NumberStats<Double>с двумя double значениями. Выведите сумму и среднее:Double sum: [sum] Double average: [average]Наконец, создайте
ComparableBox<Integer>с двумя integer значениями и выведите:Max integer: [max] Max as double: [maxAsDouble]
Вы получите четыре inputs в следующем порядке: first integer, second integer, first double, second double.
Обратите внимание, как bound T extends Number позволяет вызвать doubleValue() для вашего generic типа. С unbounded type parameter это было бы невозможно. А multiple bounds в ComparableBox гарантируют, что вы сможете и преобразовать значение в double, и сравнить значения!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Считать входные данные
int int1 = scanner.nextInt();
int int2 = scanner.nextInt();
double double1 = scanner.nextDouble();
double double2 = scanner.nextDouble();
// TODO: Создайте NumberStats<Integer> с двумя целочисленными значениями
// Выведите сумму и среднее значение в формате:
// Integer sum: [sum]
// Integer average: [average]
// TODO: Создайте NumberStats<Double> с двумя значениями double
// Выведите сумму и среднее значение в формате:
// Double sum: [sum]
// Double average: [average]
// TODO: Создайте ComparableBox<Integer> с двумя целочисленными значениями
// Выведите максимум и максимум в виде double в формате:
// Max integer: [max]
// Max as double: [maxAsDouble]
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java