为什么Map <String,Set <String >>不匹配Map <T,Set <?>>?

Alf*_*Alf 5 java generics wildcard

我有一个带有以下签名的方法:

public <T> int numberOfValues(Map<T, Set<?>> map)
Run Code Online (Sandbox Code Playgroud)

但是我不能称之为传递Map<String, Set<String>>.例如,以下内容无法编译:

Map<String, Set<String>> map = new HashMap<>();
numberOfValues(map);
Run Code Online (Sandbox Code Playgroud)

错误消息是:

numberOfValues (java.util.Map<java.lang.String,java.util.Set<?>>) in class cannot be applied to (java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)
Run Code Online (Sandbox Code Playgroud)

但是,如果我改为以下一切都很好:

public <T, V> int numberOfValues(Map<T, Set<V>> map)
Run Code Online (Sandbox Code Playgroud)

但是我对此并不感兴趣V,因为我只想知道每组的大小.

为了完整起见,这是整个方法:

public <T, V> int numberOfValues(Map<T, Set<V>> map) {
    int n = 0;
    for (T key : map.keySet()) {
        n += map.get(key).size();
    }
    return n;
}
Run Code Online (Sandbox Code Playgroud)

我知道它也可以像这样完成,但不是问题的重点:)

public <T> int numberOfValues(Map<?, Set<T>> map) {
    int n = 0;
    for (Set<T> value : map.values()) {
        n += value.size();
    }
    return n;
}
Run Code Online (Sandbox Code Playgroud)

更新:实现同样的另一种方式

public <T> int numberOfValues(Map<?, Set<T>> map) {
    int n = 0;
    for (Object key : map.keySet()) {
        n += map.get(key).size();
    }

    return n;
}
Run Code Online (Sandbox Code Playgroud)

最后更新: 感谢Jorn的回答,这是最终的实施......

public int numberOfValues(Map<?, ? extends Set<?>> map) {
    int n = 0;
    for (Set<?> value : map.values()) {
        n += value.size();
    }
    return n;
}
Run Code Online (Sandbox Code Playgroud)

Jor*_*nee 9

您错过了Set<?>也被用作通用参数的事实.仿制药是不变的.即,当参数为时Map<String, Set<?>>,传递的参数必须是精确的Map<String, Set<?>(或子类型).而Set<V>推断出类型参数.

您可以使用有界通配符来解决此问题:

public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
    ...
}
Run Code Online (Sandbox Code Playgroud)