我编写了这个方便的通用函数,用于将集合的集合转换为单个集合:
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;
}
然后我试着调用它:
List<List<String>> resultLists = ... ;
Set<String> labelsSet = CollectionsHelper.makeSet(resultLists);
我收到以下错误:
<T>makeSet(java.util.Collection<java.util.Collection<T>>) in CollectionsHelper
cannot be applied to (java.util.List<java.util.List<java.lang.String>>)
现在 List
是一个 Collection
,String
是一个 T
。那么为什么这行不通,我该如何解决呢?
最佳答案
您的签名应该是:
public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll);
基本上List<S>
不是 List<T>
的子类型只是因为S
是 T
的子类型.该属性称为 covariance 并且在 Java 中,泛型类型不是协变的(其他语言,例如 scala 包含协变泛型类型)。
你所做的没有用,因为应该可以添加任何 Collection<T>
进入Collection<Collection<T>>
,例如,使用您的签名,这将是一个有效的实现:
public static <T> Set<T> makeSet(Collection<Collection<T>> coll) {
coll.add(new HashSet<T>());
return null;
}
然后调用这个方法如下:
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
那么这会导致同样的问题吗?不!原因是编译器不允许您将任何内容添加到以未知类型参数化的集合中:
public static <T> Set<T> makeSet(Collection<? extends Collection<T>> coll) {
coll.add(new HashSet<T>()); //this line will not compile
return null;
}
拥有通配符首先是必要的,这样你就可以做你想做的事情,这可能是 Collection.addAll
的最好证明。方法被泛型化,因此 List<Number>.addAll(List<Integer>)
将被允许:
boolean addAll(Collection<? extends T> coll)
关于java - List<List<String>> 是 Collection<Collection<T>> 的实例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1772192/