为什么 Java 方法没有参数 Collection<?扩展 V> 接受设置 <V>?

Why doesn't a Java method with argument Collection<? extends V> accept Set<V>?

最近,我用了很多Guava Multimap

偶尔,我需要在 Multimap<K,V>Map<K, Collection<V> 之间进行转换。 Guava API: Multimap#asMap() 已经提供了一个方向。对于另一个方向,我写了一个简单的实用方法如下:

public static <K,V> Multimap<K,V> multimapFromMap(Map<K, Collection<V>> map) {
    Multimap<K,V> mmap = HashMultimap.create();
    for (Map.Entry<K,Collection<V>> entry : map.entrySet())
        mmap.putAll(entry.getKey(), entry.getValue());
    return mmap;
}

但是当我尝试写作时

Map<String, Set<String>> aMap = ... ; // obtained from elsewhere
Multimap<String, String> mMap = multimapFromMap(aMap);

我收到此错误消息:

multimapFromMap(java.util.Map<String, java.util.Collection<?>>) cannot be applied to (java.util.Map<java.lang.String, java.util.Set<java.lang.String>>)

但是由于 Set 接口扩展了 Collection 接口,我的代码应该没问题吧?

Oracle Java Generics tutorial page,我看到示例“... ArrayList<E> 实现 List<E>,并且 List<E> 扩展 Collection<E>。所以 ArrayList<String>List<String> 的子类型,后者是 Collection<String> 的子类型。只要您不改变类型参数,类型之间的子类型关系就会保留 ."

根据评论补充

  1. 我在 multimapFromMap 方法中用 String 替换了 V,只是为了让自己放心,我没有混淆一些与泛型相关的概念,但错误仍然存​​在 ? 替换为错误消息中的 java.lang.Object

并不是说您不能在方法需要 Collection<? extends V> 的地方使用 Set<V>,而是 Map<K, Set<V>> 不是 Map<K, Collection<V>> 的子类型。

如果您将方法更改为接受 Map<K, ? extends Collection<V>>

会起作用

在许多其他 Whosebug 问题中讨论了此原因,包括 Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?。 (打个比方,Dog就是Set<V>Animal就是Collection<V>。)