List <List <String >>是Collection <Collection <T >>的实例吗?

Mar*_*zon 8 java generics collections covariance

我编写了这个方便的通用函数,用于将集合集合转换为单个集合:

public static <T> Set<T> makeSet(Collection<Collection<T>> a_collection) {
    Iterator<Collection<T>> it = a_collection.iterator();
    Set<T> result = new HashSet<T>();
    while (it.hasNext()) {
        result.addAll(it.next());
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

然后我试着打电话给它:

    List<List<String>> resultLists = ... ;
    Set<String> labelsSet = CollectionsHelper.makeSet(resultLists);
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

<T>makeSet(java.util.Collection<java.util.Collection<T>>) in CollectionsHelper 
cannot be applied to (java.util.List<java.util.List<java.lang.String>>)
Run Code Online (Sandbox Code Playgroud)

现在a List 是a Collection,a String 是a T.那么为什么这不起作用,我该如何解决呢?

oxb*_*kes 8

你的签名应该是:

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll);
Run Code Online (Sandbox Code Playgroud)

基本上List<S>不是一个亚型List<T>,只是因为S是的一个亚型T.该属性称为协方差,在Java中,泛型类型不是协变的(其他语言如scala包含协变泛型类型).

你做了什么没有用,因为它应该可以添加任何Collection<T>一个Collection<Collection<T>>,所以例如,你的签名,这将是一个有效的实现:

public static <T> Set<T> makeSet(Collection<Collection<T>> coll) {
    coll.add(new HashSet<T>());
    return null;
}
Run Code Online (Sandbox Code Playgroud)

但是后来调用这个方法如下:

List<List<String>> outside = new LinkedList<List<String>>();
makeSet(outside); //actually this line will not compile!
List<String> oops = outside.get(0); //oh dear - it's a HashSet
Run Code Online (Sandbox Code Playgroud)

那么这会导致同样的问题吗?没有!原因是编译器不允许您在未知类型参数化的集合中添加任何内容:

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll) {
    coll.add(new HashSet<T>()); //this line will not compile
    return null;
}
Run Code Online (Sandbox Code Playgroud)

首先需要使用通配符,以便您可以执行类似于您想要执行的操作,可能最好地通过该Collection.addAll方法的生成方式进行说明,以便List<Number>.addAll(List<Integer>)允许:

boolean addAll(Collection<? extends T> coll)
Run Code Online (Sandbox Code Playgroud)


Boz*_*zho 7

public static <T> Set<T> makeSet(Collection<? extends Collection<T>> a_collection) {
    Iterator<? extends Collection<T>> it = a_collection.iterator();
    Set<T> result = new HashSet<T>();
    while (it.hasNext()) {
            result.addAll(it.next());
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)