Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Wildcard в Generics
Wildcard (подстановочный символ) — это механизм в Java, который позволяет работать с параметризованными типами более гибко. Обозначается символом `?` (вопросительный знак) и используется для создания переменных типов, способных принимать различные конкретные типы.
Три основные формы Wildcard
1. Unbounded Wildcard (?)
Допускает любой тип. Используется, когда тип параметра не важен:
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
Можно передать List<String>, List<Integer>, List<Object> — любой список.
2. Upper Bounded Wildcard (? extends Type)
Ограничивает тип сверху. Параметр должен быть подклассом указанного типа:
public double sumNumbers(List<? extends Number> numbers) {
double sum = 0;
for (Number num : numbers) {
sum += num.doubleValue();
}
return sum;
}
Анализ:
- Можно передать
List<Integer>,List<Double>,List<BigDecimal> - Не можно передать
List<String> - Можно только читать элементы (безопасно, так как знаем, что это Number)
- Нельзя добавлять элементы (кроме null), так как конкретный тип неизвестен
3. Lower Bounded Wildcard (? super Type)
Ограничивает тип снизу. Параметр должен быть суперклассом указанного типа:
public void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
Анализ:
- Можно передать
List<Integer>,List<Number>,List<Object> - Можно добавлять Integer (и его подклассы)
- При чтении получаем Object, так как конкретный тип сверху неизвестен
Принцип PECS (Producer Extends, Consumer Super)
Это золотое правило для выбора вида wildcard:
- extends — используй, если структура данных производит элементы (только чтение)
- super — используй, если структура данных потребляет элементы (только запись)
// Producer: читаем из List
public void readData(List<? extends Number> source) {
Number value = source.get(0); // ✓ работает
}
// Consumer: пишем в List
public void writeData(List<? super Integer> dest) {
dest.add(42); // ✓ работает
}
Практические примеры
Копирование коллекций:
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (T item : src) {
dest.add(item);
}
}
Здесь:
src— producer (читаем из неё)dest— consumer (пишем в неё)
Отличие от Type Parameters
// Type parameter — конкретный тип на весь метод
public <T> void method(List<T> list) {
T item = list.get(0);
}
// Wildcard — гибкий, но неизвестный тип
public void method(List<?> list) {
Object item = list.get(0); // только Object
}
Ограничения Wildcard
- Нельзя использовать wildcard в конструкторах
- Нельзя создавать массивы параметризованных типов с wildcard
- Wildcard не может использоваться в type bound одного wildcard
Заключение
Wildcard — это мощный инструмент для написания гибких и безопасных API, которые работают с различными типами данных. Правильное использование extends и super делает код более универсальным и соответствующим принципам SOLID.