Подстановка ? super
Подстановка ? super - это wildcard-тип с нижней границей
в обобщённых типах Java. Она означает «неизвестный тип,
который является супертипом указанного типа». Такой wildcard
применяется, когда нужно безопасно записывать значения
в обобщённую структуру. В первом параметре указывается
ключевое слово super, а во втором - тип, который
выступает нижней границей.
Wildcard ? super противоположен по смыслу
wildcard ? extends. Если ? extends позволяет
безопасно читать значения, то ? super позволяет
безопасно записывать значения. Это связано с принципом
PECS: Producer Extends, Consumer Super.
Синтаксис
List<? super Type>
Consumer<? super Type>
Comparable<? super Type>
Пример
Давайте запишем значения в список с типом
List<? super Integer>. Такой список может быть
списком объектов Integer, Number или
Object:
import java.util.List;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
List<Number> nums = new ArrayList<>();
addNumbers(nums);
System.out.println(nums);
}
public static void addNumbers(List<? super Integer> list)
{
list.add(1);
list.add(2);
list.add(3);
}
}
Результат выполнения кода:
[1, 2, 3]
Пример
Давайте передадим в метод список объектов
Object, так как Object является супертипом
для Integer:
import java.util.List;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
List<Object> objects = new ArrayList<>();
addNumbers(objects);
System.out.println(objects);
}
public static void addNumbers(List<? super Integer> list)
{
list.add(1);
list.add(2);
list.add(3);
}
}
Результат выполнения кода:
[1, 2, 3]
Пример
Особенность ? super в том, что из такой структуры
нельзя безопасно читать значения, потому что компилятор
знает только верхнюю границу в виде Object.
Давайте убедимся, что добавление работает, а результат
чтения имеет тип Object:
import java.util.List;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
List<Number> nums = new ArrayList<>();
nums.add(10);
Object res = getFirst(nums);
System.out.println(res);
}
public static Object getFirst(List<? super Integer> list)
{
list.add(1);
return list.get(0);
}
}
Результат выполнения кода:
10
Пример
Давайте напишем обобщённый метод, который копирует
элементы из одного списка в другой с использованием
? super для приёмника:
import java.util.List;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
List<Integer> src = List.of(1, 2, 3, 4, 5);
List<Number> dst = new ArrayList<>();
copy(src, dst);
System.out.println(dst);
}
public static <T> void copy(List<? extends T> src, List<? super T> dst)
{
for (T item : src)
{
dst.add(item);
}
}
}
Результат выполнения кода:
[1, 2, 3, 4, 5]
Смотрите также
-
подстановка
? extends,
которая задаёт верхнюю границу типа -
подстановка
?,
которая обозначает неизвестный тип -
ключевое слово
super,
которое задаёт нижнюю границу в обобщениях -
контравариантность
Contravariant,
которая лежит в основе подстановки ? super