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