流中的泛型参数returns List<ChildInterface>,但直接方法调用returns List<Parent>

Generic parameter returns List<ChildInterface> in stream, but direct method call returns List<Parent>

对于设置,我有:

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 return是一个List<Parent>(不应该是return 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 是 returning a List<Child1>。我不明白为什么,因为流的实现根本没有改变——除了启动它的 childList 通过通用参数,而不是直接调用 MyClass 的私有成员字段。

那么为什么他们 return 是两种不同的东西?

(这个例子很混乱。Meeting真的是Parent吗?)

getChild1List 的第一个版本中,collect(toList()) 方法在 Stream<Child1> 及其目标类型上调用——由 return 类型决定 getChild1List——是List<Parent>。这是有效的,因为它允许类型 T 的流由 T 的超类型的收集器收集。更具体地说,您将类型 Child1 的实例添加到 List<Parent> 类型 -安全并被允许。您也可以将 getChild1List() 的声明更改为 return List<Child1> 而不是 List<Parent>.

您可以通过查看 Stream<T>collect() 的声明来了解允许差异的位置:

<R,A> R collect(Collector<? super T,A,R> collector)

? super T 允许差异。

您对 returnsListByContact

的声明
<T extends Parent> List<T> returnsListByContact(List<T> childList, ...)

允许差异。它采用 List<T> 和 return 类型的参数 List<T>。参数和 return 类型必须相同。这就是为什么当您传入 List<Child1> 并尝试从 return 类型为 List<Parent> 的方法 return 时出现不匹配的原因——这些类型不兼容。

要解决此问题,您需要在 returnsListByContact 的声明中添加一些差异。这是我的做法:

<T extends Parent> List<T> returnsListByContact(List<? extends T> childList, ...)

这允许您在传递某些子类型的列表时 return 某种类型的列表,在这种情况下 returning List<Parent> 同时传递 List<Child1> ,这就是我想你想要的。