对于设置,我有:
interface Parent
interface Child1 extends Parent
interface Child2 extends Parent
我在其他地方:
public class MyClass {
private List<Child1> child1List = new ArrayList<>();
public List<Parent> getChild1List(Contact contact) {
return child1List.parallelStream()
.filter(m -> m.getContacts().contains(contact))
.sorted(Comparator.comparing(Parent::getParentField))
.collect(Collectors.toList());
}
}
当我这样做时,getChild1List返回List<Parent>
(不应该返回List<Child1>
?)
后来,我发现该流对其他方法很有用,所以我提取它并用它构建了一个泛型方法。我有多个扩展Parent的接口,所以我做了如下:
private <T extends Parent> List<T> returnsListByContact(List<T> childList, Contact contact) {
return childList.parallelStream()
.filter(m -> m.getContacts().contains(contact))
.sorted(Comparator.comparing(Parent::getParentField))
.collect(Collectors.toList());
}
和getChild1List(Contact contact)
成了:
public List<Parent> getChild1List(Contact contact) {
return returnsListByContact(child1List, contact);
}
但现在它并不喜欢这样,引用getChild1List返回List<Child1>
。我不明白为什么,因为流的实现根本没有改变 - 除了启动它的childList来自通用参数,而不是直接调用MyClass的私有成员字段。
那他们为什么要回归两件事?
答案 0 :(得分:5)
(这个例子令人困惑。Meeting
真的是Parent
吗?)
在getChild1List
的第一个版本中,在collect(toList())
上调用Stream<Child1>
方法,其目标类型(由getChild1List
的返回类型确定 - 是List<Parent>
。这是有效的,因为允许T超类型的收集器收集类型为T的流。更具体地说,您要将类型为Child1
的实例添加到List<Parent>
类型 - 安全,是允许的。您也可以将getChild1List()
的声明更改为返回List<Child1>
而不是List<Parent>
。
您可以通过查看collect()
中Stream<T>
的声明来查看允许差异的位置:
<R,A> R collect(Collector<? super T,A,R> collector)
? super T
是允许差异的原因。
您对returnsListByContact
,
<T extends Parent> List<T> returnsListByContact(List<T> childList, ...)
不允许差异。它采用List<T>
类型的参数并返回List<T>
。参数和返回类型必须相同。这就是为什么传入List<Child1>
并尝试从返回类型为List<Parent>
的方法返回它时不匹配的原因 - 这些类型不兼容。
要解决此问题,您需要在returnsListByContact
声明中添加一些差异。我就是这样做的:
<T extends Parent> List<T> returnsListByContact(List<? extends T> childList, ...)
这允许您在传递某个子类型的列表时返回某种类型的列表,在这种情况下,在传入List<Parent>
时返回List<Child1>
,这是我认为您想要的。