为什么不Map <string,set <string =“”>&gt;匹配Map <t,设置<?=“”>&gt;?

时间:2016-11-08 14:30:21

标签: java generics wildcard

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

public <T> int numberOfValues(Map<T, Set<?>> map)

但我不能称它在Map<String, Set<String>>中传递。例如,以下内容无法编译:

Map<String, Set<String>> map = new HashMap<>();
numberOfValues(map);

错误信息是:

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>>)

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

public <T, V> int numberOfValues(Map<T, Set<V>> map)

但是我对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;
}

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

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

更新:另一种实现相同的方法

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

    return n;
}

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

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

2 个答案:

答案 0 :(得分:10)

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

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

public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
    ...
}

答案 1 :(得分:0)

提示:

numberOfValues方法中,编写类似

的内容是完全合法的
Set<Object> set = new HashSet<>();
set.add(1);
set.add("Powned");
map.put(null, set);

您可以使用地图中已有的合适的密钥替换null以进行有效的映射,从而彻底打破周围代码中的类型安全性。

推断或明确定义集合的类型,或添加通配符绑定以防止变异地图访问(如? extends Set<?>