Пытаюсь написать параметризуемый метод, принимающий параметризованные типы:
public static <T> void findMinMax(
Stream<? extends T> stream,
Comparator<? super T> comparator,
BiConsumer<? super T, ? super T> minMaxConsumer
) {
Stream<T> sortedStream = stream.sorted(comparator);
}
Объявление метода имею из условия задачи. Непонятны две вещи:
Не понимаю почему stream может параметризоваться любым подтипом T, а comparator любым родительским типом T. То есть почему у stream тип Stream<? extends T>, а у comparator - Comparator<? super T>? С какой целью это сделано?
В данный момент при компиляции вылетает ошибка:
error: incompatible types: Stream<CAP#1> cannot be converted to Stream<T>
Stream<T> sortedStream = stream.sorted(comparator);
^
where T is a type-variable:
T extends Object declared in method <T>findMinMax(Stream<? extends T>,Comparator<? super T>,BiConsumer<? super T,? super T>)
where CAP#1 is a fresh type-variable:
CAP#1 extends T from capture of ? extends T
Не могу понять, что не так. Ведь T является и своим подтипом и своим супер-типом. Почему тогда компилятор говорит о несовместимости типов? Что компилятор подразумевает под CAP#1?
Generics (Обобщенные типы) инвариантны, то есть нельзя присвоить к Stream<Number> ссылку на Stream<Double>. Wildcard (Маска) придает свойство вариантности при взаимодействии с обобщенными типами рассматривая их либо как источники объектов Т (Producer Extends, см. PECS), либо как приёмники Т (Consumer Super, см. PECS).
Wildcard это не Generic, это специальный тип параметризации, его можно использовать только при декларировании переменных или аргументов методов, все Wildcard содержат вопросительный знак - ?.
Инвариантный Generic (Обобщенный тип):
List<T> - List принимает T и его наследников, и возвращает объекты Т.
Ковариантность достигается через Upper Bounded Wildcards ? extends T:
List<? extends T> - List возвращает объекты Т, так как содержит объекты Т либо наследников Т:
List<? extends Number> numbers = new ArrayList<Double>() {{ add(2.5); }};
Number n = numbers.get(0);
Контравариантность достигается через Lower Bounded Wildcards ? super T:
List<? super T> - List принимает объекты T и его наследников:
List<? super Number> objects = new ArrayList<Object>() {{ add(2.5); add("it's fine!"); }}
objects.add((short) 256);
Этот wildcard указывает, что исходный List может содержать что угодно, вплоть до Object, по этой причине метод get(n) вернет Object, но wildcard позволит передать в List объекты с типом Number и его наследников.
Разбор ошибки:
public static <T> void findMinMax(Stream<? extends T> stream) {
Stream<T> sortedStream = stream.sorted(comparator);
}
Ошибка из-за попытки присвоить Upper Bounded Wildcards к типу Stream.
Почему так сделать нельзя:
List<? extends Number> containsNumbers = new ArrayList<Double>();
containsNumbers.add(new Integer(100)); // Ошибка, wildcard `? extends Number` позволяет только прочитать объекты типа `Number`.
List<Number> numbers = containsNumbers // Ошибка, нельзя присвоить List<? extends Number>
numbers.add(new Integer(200)); // если бы не ошибка выше, то можно было бы добавить объект неподходящего типа
Продвижение своими сайтами как стратегия роста и независимости