Вы правы, что типы не совместимы с присвоением.
В сомнении, это легко проверить:
List<Object> a = null;
List<NamePhone> b = null;
a = b; // Error!
Причинапочему кажется совместимым с назначением в этом случае - это вывод целевого типа .Процесс вывода может быть сложным, особенно в этом случае, который включает Collector
, который имеет параметры типа три .
Я постараюсь уточнить соответствующие части здесь:
Подпись метода collect
выглядит следующим образом:
<R, A> R collect(Collector<? super T, A, R> collector);
Это вызывается наStream<T>
экземпляр.В вашем случае это Stream<NamePhone>
.Но обратите внимание, что сам метод имеет дополнительные общие параметры, а именно R
и A
.Соответствующим здесь является R
, который является типом возврата .
Передается Collector
, созданный методом toList
, который выглядит следующим образом:
public static <T> Collector<T, ?, List<T>> toList()
Он также является общим.Параметр типа в основном будет «замещен» на основе context , в котором вызывается метод.
Поэтому, когда вы напишите это:
List<NamePhone> npList = nameAndPhone.collect(Collectors.toList());
, тогда у вас будут следующие назначения типа:
-
T
из Stream
равно NamePhone
T
Collector
равно NamePhone
R
collect
метода равно List<NamePhone>
Но вы также можете написать
List<Object> npList = nameAndPhone.collect(Collectors.toList());
В этом случае
-
T
из Stream
равно NamePhone
T
изCollector
равно Object
R
метода collect
равно List<Object>
Обратите внимание, что это возможно только потому, что метод collect
принимаетCollector<? super T, ...>
.Это не сработало бы, если бы оно ожидало Collector<T, ...>
.Это в основном означает, что вы можете использовать элементы из Stream
и собрать их в новый List
, если параметр типа нужного списка представляет собой супертип элементов в потоке.
Концептуально, это имеет смысл, потому что это в некотором роде аналогично
List<Integer> integers = ...;
List<Number> numbers = ...;
for (Integer i : integers) numbers.add(i); // This should work as well!