Java将java.lang.Object列表中的特定类列表添加到java 8流中 - 为什么?

use*_*795 8 java generics inheritance java-8 java-stream

public class Test {

    static List<Object> listA = new ArrayList<>();

    public static void main(final String[] args) {
        final List<TestClass> listB = new ArrayList<>();
        listB.add(new TestClass());

        // not working
        setListA(listB);

        // working
        setListA(listB.stream().collect(Collectors.toList()));

        System.out.println();
    }

    private static void setListA(final List<Object> list) {
        listA = list;
    }

}
Run Code Online (Sandbox Code Playgroud)

为什么它适用于流,并不适用于简单的集合?

Oli*_*rth 8

对于第一种情况,它失败,因为List<TestClass>它不是子类型List<Object>.1

对于第二种情况,我们有以下方法声明:

interface Stream<T> {
    // ...
    <R, A> R collect(Collector<? super T, A, R> collector)
}
Run Code Online (Sandbox Code Playgroud)

和:

class Collectors {
    // ...
    public static <T> Collector<T, ?, List<T>> toList()
}
Run Code Online (Sandbox Code Playgroud)

这允许Java从上下文中推断泛型类型参数.2在这种情况下List<Object>推断RObjectT.

因此,您的代码等同于:

Collector<Object, ?, List<Object>> tmpCollector = Collectors.toList();
List<Object> tmpList = listB.stream().collect(tmpCollector);
setListA(tmpList);
Run Code Online (Sandbox Code Playgroud)

1.见这里.

2.参见此处此处.

  • @OliverCharlesworth作为一名教师,我自己,我总是欣赏一位知识渊博的工程师说"我不知道".这是一件很重要的事情,我希望世界上更多的人能够做到这一点. (4认同)
  • @Thomas - 简单地说`List <TestClass>`不是`List <Object>`的子类型,因此赋值失败. (2认同)
  • @KlitosKyriacou类型推断使用称为表达式的*目标类型*的东西.对于方法调用表达式,目标类型通常是指定返回值的任何值,在本例中是另一个方法的参数.`collect`的目标类型是`setListA`的`List <Object>`,`toList`的目标类型是`Collector <?超级T,A,R>``收集`.我认为Javac必须首先在这里推断出`collect`的类型,只是基于这个代码编译的事实,但是自从我阅读了JLS的这一部分以来已经有一段时间了. (2认同)