Java将特定类的列表添加到java.lang.Object列表中,与java 8 streams一起工作 – 为什么?

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; } } 

为什么它与流一起工作,并不适用于简单的设置?

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

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

 interface Stream<T> { // ... <R, A> R collect(Collector<? super T, A, R> collector) } 

和:

 class Collectors { // ... public static <T> Collector<T, ?, List<T>> toList() } 

这允许Java从上下文中推断泛型类型参数。 2在这种情况下,对于R推导List<Object> ,对于T推导Object

因此你的代码等同于:

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

看这里例如。

2.看这里或这里 。

这条线

 setListA(listB); 

因为Java中的List是不变的, 所以TestClass扩展Object时, List<TestClass> 不会扩展 List<Object> 。 更多细节在这里

这条线

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

因为Java从这个方法签名setListA(final List<Object> list)推断出Collector的泛型类型的setListA(final List<Object> list) ,所以你实际上通过了List<Object>

Java Generic的类型参数是不变的 ,这意味着它不能被继承为类型参数类层次结构。 List<TestClass>List<Object>的公共父项是List<?>

泛型继承

你可以从kotlin & java看到有关Java通用通配符的详细答案。 例如:

  List<String> strings = new ArrayList<String>(); List<CharSequence> sequences = strings; // can't work List<? extends CharSequence> parent1 = strings; // works fine List<?> parent2 = strings; // works fine // ^--- is equaivlent to List<? extends Object> 

流方法是将List<TestClass>List<Object> 。 如果你想它的工作原理,而不是通过流转换List到另一个List 。 你的方法签名应该如下,并且Collection#addAll也可以在java中使用:

 List<?> listA = new ArrayList<>(); private static void setListA(List<?> list) { listA = list; }