Обобщенные методы
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 55 из 87.
В то время как универсальные классы позволяют целым классам работать с различными типами, иногда требуется, чтобы универсальным был только один метод. Универсальный метод объявляет свой собственный параметр типа, независимый от любых универсальных параметров на уровне класса.
Параметр типа указывается перед типом возвращаемого значения в сигнатуре метода:
public class Utility {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
String[] names = {"Alice", "Bob"};
Integer[] numbers = {1, 2, 3};
Utility.printArray(names); // Работает с String[]
Utility.printArray(numbers); // Работает с Integer[]Обратите внимание на <T>, расположенный между модификаторами и типом возвращаемого значения. Это объявляет T как параметр типа для этого конкретного метода. Компилятор выводит фактический тип из переданных вами аргументов.
Обобщенные методы также могут возвращать обобщенный тип:
public static <T> T getFirst(T[] array) {
if (array.length > 0) {
return array[0];
}
return null;
}
String first = getFirst(new String[]{"a", "b"}); // Возвращает "a"Вы можете использовать несколько параметров типа, когда это необходимо:
public static <K, V> void printPair(K key, V value) {
System.out.println(key + ": " + value);
}
printPair("Age", 25); // String и Integer
printPair(1, "First"); // Integer и StringОбобщенные методы особенно полезны в утилитарных классах, где требуются гибкие, повторно используемые операции без необходимости создания обобщенного класса.
Задание
ЛегкоДавайте создадим набор утилит, который продемонстрирует гибкость универсальных (generic) методов. Вы создадите класс с переиспользуемыми методами, которые работают с любым типом данных, показывая, как универсальные методы могут существовать независимо от универсальных классов.
Вы организуете свой код в двух файлах:
ArrayUtils.java: Создайте вспомогательный класс, содержащий универсальные методы для работы с массивами. Ваш класс должен иметь три статических универсальных метода:getLast— универсальный метод, который принимает массив типаTи возвращает последний элемент. Если массив пуст, вернитеnull.swap— универсальный метод, который принимает массив типаTи два целочисленных индекса, а затем меняет местами элементы в этих позициях. Этот метод ничего не возвращает.printWithLabel— универсальный метод с двумя параметрами типаKиV. Он принимает метку типаKи значение типаV, а затем выводит их в формате:[label]: [value]Main.java: Примените ваши универсальные методы на практике! Вы получите четыре входных значения: два слова (Strings) и два числа (integers).Сначала создайте массив
String[], содержащий оба слова. ИспользуйтеgetLast, чтобы получить последний элемент, и выведите:Last word: [result]Затем создайте массив
Integer[], содержащий оба числа. Вызовитеswap, чтобы поменять местами элементы с индексами 0 и 1, затем выведите:After swap: [first], [second]Наконец, продемонстрируйте работу универсального метода с двумя параметрами, вызвав
printWithLabelдважды:- Один раз с первым словом в качестве метки и первым числом в качестве значения
- Один раз с первым числом в качестве метки и вторым словом в качестве значения
Вы получите четыре входных значения по порядку: первое слово, второе слово, первое число, второе число.
Обратите внимание, как каждый метод объявляет свои собственные параметры типа с помощью <T> или <K, V> перед типом возвращаемого значения. Компилятор выводит фактические типы из аргументов, которые вы передаете — нет необходимости указывать их явно при вызове методов!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Считать входные данные
String firstWord = scanner.nextLine();
String secondWord = scanner.nextLine();
int firstNumber = scanner.nextInt();
int secondNumber = scanner.nextInt();
// TODO: Создать массив String[], содержащий оба слова
// TODO: Использовать ArrayUtils.getLast, чтобы получить последний элемент
// Вывести: "Last word: [result]"
// TODO: Создать массив Integer[], содержащий оба числа
// TODO: Вызвать ArrayUtils.swap, чтобы поменять местами элементы с индексами 0 и 1
// Вывести: "After swap: [first], [second]"
// TODO: Вызвать ArrayUtils.printWithLabel, используя firstWord в качестве метки и firstNumber в качестве значения
// TODO: Вызвать ArrayUtils.printWithLabel, используя firstNumber в качестве метки и secondWord в качестве значения
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»