Java泛型:需要捕获#67的?

Fro*_*cho 1 java generics

我有这个功能:

 /**
 * 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,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
Run Code Online (Sandbox Code Playgroud)

(由于Java解包,int不是问题,我也试过使用Integers但它没有用).

Joh*_*ica 7

问题是协方差问题.从一个地图中拉出一个键时,无法保证该键与其他地图兼容.如果一个地图使用Foos而另一个地图使用Bars并且这两个类彼此无关,则您无法互换它们.

想象一下a是类型Map<String, Integer>而b是类型Map<Float, Integer>.这两种类型与您的参数声明兼容,但它们的键类型不兼容.如果Float从b获取a并尝试将其用作键,则会遇到麻烦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));
    }
}
Run Code Online (Sandbox Code Playgroud)

一般来说,如果你想苏斯出了问题?,也没有精神上取代?Object.相反,更好的思考方法是?用不同的虚构类型名称替换每个实例.

警告:数学类比

它类似于C常数,它出现在微积分中的不定积分中.例如,∫COS X d X = SIN X + C ^.如果你做一个积分然后写C就好了,但是如果你做多个积分那么你必须记住这些常量是不同的并且是不可互换的.那么你应该写C 1,C 2,C 3等.

?是一样的.第一次出现,假装它是class A.下一次是class B.等等.

  • 虽然它是有效的 - 我想我更喜欢`<K>`而不是`<Key>`,`Key`看起来很像一个类名,但它是一个类型变量. (3认同)