我有这个功能:
/**
* Helper function that adds the values of b to the elements of a, treating
* all keys that exist in b but not in a, as existent in a with value 0. NB:
* It operates IN PLACE.
* @param a The {@link java.util.Map} which will hold the result
* @param b The {@link java.util.Map} which will be added to a
*/
private static void sumMaps(Map<?, Integer> a, Map<?,Integer> b)
{
for (Object key : b.keySet()) {
Integer currentCount = a.get(key);
a.put(key, currentCount == null ? b.get(key) : currentCount + b.get(key));
}
}
但是,NetBeans在for的最后一行突出显示“key”,并给出了这个错误:
method put in class java.util.Map<K,V> cannot be applied to given types
required: capture #67 of?, java.lang.Integer
found: java.lang.Object, int
(由于Java解包,int不是问题,我也试过使用Integers但它不起作用)。
答案 0 :(得分:7)
问题在于协方差。从一个地图中拉出一个键时,无法保证该键与其他地图兼容。如果一个地图使用Foo
,而另一个地图使用Bar
,并且这两个类彼此无关,那么您就无法互换它们。
想象一下,a类型为Map<String, Integer>
,b类型为Map<Float, Integer>
。这两种类型与您的参数声明兼容,但它们的键类型不兼容。如果您从b中获取Float
并尝试将其用作a.put(key,...)
中的密钥,则会遇到问题。这实际上是编译器所抱怨的。使用?
不会将地图限制为兼容的密钥类型。
您必须通过将两个关键类设置为某个通用?
类来指定两个关键类,而不是Key
。这样,来自一个地图的键可以插入到另一个地图的键中。
private static <Key> void sumMaps(Map<Key, Integer> a, Map<Key, Integer> b)
{
for (Key key : b.keySet()) {
Integer currentCount = a.get(key);
a.put(key, currentCount == null ? b.get(key) : currentCount + b.get(key));
}
}
一般来说,如果您尝试使用?
解决问题,请不在心理上将?
替换为Object
。相反,考虑它的更好方法是用不同的虚构类型名称替换?
的每个实例。
警告:数学类比
它类似于 C 常量,它出现在微积分中的不定积分中。例如,∫cos x d
?
也是一样的。第一次出现时,假装它是class A
。下次是class B
。等等。
答案 1 :(得分:3)
?
不是Object
或其他内容。这完全不为人知。好吧,我不是很擅长解释那些东西,但似乎有一个非常简单的解决方案:既然两个Map
的键需要是相同的类型,为什么不引入泛型类型变量呢?
private static <T> void sumMaps(Map<T, Integer> a, Map<T, Integer> b) {
for (T key : b.keySet()) {
Integer currentCount = a.get(key);
a.put(key, currentCount == null ? b.get(key) : currentCount
+ b.get(key));
}
}
答案 2 :(得分:3)
指定“?”对于密钥意味着它可以是任何类型,但每个Map的密钥必须相同才能使此方法起作用。所以请改用以下内容:
private static <K> void sumMaps(Map<K, Integer> a, Map<K, Integer> b) {
for (K key : b.keySet()) {
Integer currentCount = a.get(key);
a.put(key, currentCount == null ? b.get(key) : currentCount + b.get(key));
}
}
答案 3 :(得分:2)
对于?
读取“某些特定类型”并注意,每次提及?
时,这可能是不同的类型。因此,例如,a
可以是Map<String, Integer>
,b
可以是Map<BigDecimal, Integer>
。所以,实际上,你不应该被允许从a
中取出一个密钥并将其放入b
并且编译器阻止你。编译器在解释这个问题时没什么帮助!
正如其他答案所暗示的那样,您可以将该方法设为通用。
答案 4 :(得分:1)
对象不是?的有效替代品。 这是一个带有类型变量T的工作版本:
private static <T> void sumMaps(final Map<T, Integer> a,
final Map<T, Integer> b){
for(final T key : b.keySet()){
final Integer currentCount = a.get(key);
a.put(key,
currentCount == null
? b.get(key)
: Integer.valueOf(currentCount.intValue()
+ b.get(key).intValue()));
}
}
(我还删除了一些自动装箱/拆箱)