Разбор использования вопросительного знака в Java Generics
Быстрый ответ
В параметрах типа обобщений в Java символ вопроса ?
обозначает неизвестный тип или так называемый метасимвол подстановки. Он позволяет реализовать гибкость в управлении типами данных, когда не требуется указание точных типовых границ. Если нам нужно работать с типом T
или его подтипами, мы используем ? extends T
, что позволяет читать данные, но не разрешает добавление новых элементов. В свою очередь, ? super T
применяется для вставки экземпляров типа T
или его супертипов в коллекцию. Такое использование обеспечивает гибкость кода и смягчает догматичность типовых ограничений. Пример кода ниже демонстрирует использование ограниченного метасимвола подстановки:
public void sum(List<? extends Number> numbers) {
double total = 0.0;
for(Number n : numbers) {
total += n.doubleValue(); // Да, складывать так просто!
}
}
Два случая использования метасимвола подстановки: часто непонятные концепции
Применяем ? extends T
Выражение ? extends T
становится вашим ключом в работе с классами, которые являются подтипами T
. Это может служить направляющим компасом к тем методам, которые определены в T
или его наследниках. Использование такого метасимвола подстановки дает вам гибкость в работе с различными типами данных. Кто бы отказался от такой универсальности? 😏
public void printFirst(List<? extends HasWord> list) {
if (!list.isEmpty()) {
HasWord first = list.get(0);
System.out.println(first); // Раскройся, истинный HasWord!
}
}
List<Sentence> sentences = ...;
printFirst(sentences); // Вау! Sentence реализует HasWord.
Празднуем с ? super T
Когда вам требуется добавить объекты типа T
или его подтипов в коллекцию, используйте ? super T
. Этот подход лежит в основе концепции PECS (Producer Extends, Consumer Super) и гарантирует, что ваш метод сможет обработать коллекции, вмещающие T
или более распространенный тип. Такая щедрость превращает отдых в настоящий праздник 🎅:
public void fillWithDefaultWords(List<? super Sentence> list) {
list.add(new Sentence("default")); // Sentence для всех, как в шоу Опры!
}
List<HasWord> words = ...;
fillWithDefaultWords(words); // HasWord – родитель Sentence, всё на месте!
Визуализация
// Ваши обобщения – как комната с дверью, пометка на которой обозначает T
Room<T> 🏠🚪
// Метасимвол подстановки допускает ЛЮБОЙ тип двери
Room<?> 🏠🎟️
Ключевая мысль: Метасимвол подстановки ?
обозначает неизвестный тип. Это ваш всемогущий проходной билет, который подходит к любому типу!
| Обобщение | Принимает Тип Двери |
| ----------------- | ----------------- |
| Room<ConcreteDoor>| 🚪(Только конкретная) |
| Room<?> | 🚪🚪🚪(Любой тип!) |
Ограниченные метасимволы подстановки: мастера всех дел
Ограниченные метасимволы подстановки ? extends T
и ? super T
позволяют выразить ваши намерения точнее и являются предпочтительными в сравнении с неограниченными метасимволами подстановки или "сырыми" типами. Это ваш прямой билет к лучшему дизайну и более безопасному коду. Например, алгоритмы сортировки могут использовать Comparator<? super T>
:
Collections.sort(list, new Comparator<SomeClass>() {
public int compare(SomeClass o1, SomeClass o2) {
// Секреты сравнения под бронеплитой!
}
});
Таким образом, компаратор будет работать с кодом класса SomeClass
или его суперклассами.
Жизненные уроки по типам
- Применять
? extends T
для обеспечения безопасного чтения данных, опустив добавление элементов наугад. - Дать приоритет
? super T
для вставки элементов, без нарушения контрактов исходного типа. - Нет необходимости в
instanceof
при использовании ограниченных метасимволов подстановки; полиморфизм становится нашим другом.
День из жизни обобщений
Представим себе разработчика API, работающего с разнообразием типов данных. Ограниченные метасимволы подстановки приводят к созданию универсальных методов:
public <E> void processData(Collection<? extends E> data) {
for (E element : data) {
// обработка элемента как вам угодно
}
}
Теперь ваша Collection
может вместить любой подтип E
. Победа достигнута!
Полезные материалы
- Метасимволы подстановки в Java (учебник Oracle) – авторитетный источник знаний о обобщениях и метасимволах подстановки от бренда Oracle.
- Когда использовать обобщения, а когда метасимволы подстановки? (Stack Overflow) – практичные советы и рекомендации от профессионального сообщества разработчиков.
- Обобщённые типы в Java (DigitalOcean) – обучающий материал по применению метасимволов подстановки в обобщениях.
- Обобщения в Java (Tutorialspoint) – глубокое погружение в возможности и механизмы работы с обобщениями в Java.
- DZone – разведка в мире обобщений и метасимволов подстановки в Java с новой перспективы.