为什么 Map<String, Set<String>> 不匹配 Map<T, Set<?>>?
Why doesn’t Map<String, Set<String>> match Map<T, Set<?>>?
我有一个具有以下签名的方法:
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;
}
您忽略了 Set<?>
也用作通用参数这一事实。泛型是不变的。即,当参数为 Map<String, Set<?>>
时,传递的参数必须恰好为 Map<String, Set<?>
(或其子类型)。而使用 Set<V>
类型参数是推断出来的。
您可以使用有界通配符解决此问题:
public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
...
}
提示:
在你的 numberOfValues
方法中,写
这样的东西是完全合法的
Set<Object> set = new HashSet<>();
set.add(1);
set.add("Powned");
map.put(null, set);
您可以将 null
替换为映射中已有的合适键以进行有效映射,从而完全破坏周围代码中的类型安全。
推断或显式定义集合的类型,或添加通配符绑定以防止更改映射访问(如 ? extends Set<?>
)
我有一个具有以下签名的方法:
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;
}
您忽略了 Set<?>
也用作通用参数这一事实。泛型是不变的。即,当参数为 Map<String, Set<?>>
时,传递的参数必须恰好为 Map<String, Set<?>
(或其子类型)。而使用 Set<V>
类型参数是推断出来的。
您可以使用有界通配符解决此问题:
public <T> int numberOfValues(Map<T, ? extends Set<?>> map) {
...
}
提示:
在你的 numberOfValues
方法中,写
Set<Object> set = new HashSet<>();
set.add(1);
set.add("Powned");
map.put(null, set);
您可以将 null
替换为映射中已有的合适键以进行有效映射,从而完全破坏周围代码中的类型安全。
推断或显式定义集合的类型,或添加通配符绑定以防止更改映射访问(如 ? extends Set<?>
)