HashMap的关键问题

时间:2010-06-12 16:42:24

标签: java key hashmap

我正在分析一些旧的Java代码,看来我使用静态HashMap和访问方法缓存值不起作用。

缓存代码(有点抽象):

static HashMap<Key, Value> cache = new HashMap<Key, Value>();

public static Value getValue(Key key){
    System.out.println("cache size="+ cache.size());                
    if (cache.containsKey(key)) {
        System.out.println("cache hit");
        return cache.get(key);
    } else {
        System.out.println("no cache hit");
        Value value = calcValue();
        cache.put(key, value);
        return value;
    }
}

分析代码:

for (int i = 0; i < 100; i++)
{ 
    getValue(new Key());
}

结果输出:

 cache size=0
 no cache hit
 (..)
 cache size=99
 no cache hit

它看起来像Key的哈希代码或等于代码中的标准错误。 但是:

 new Key().hashcode == new Key().hashcode // TRUE
 new Key().equals(new Key()) // TRUE

特别奇怪的是cache.put(key, value)只是为hashmap添加了另一个值,而不是替换当前的值。

所以,我真的不知道这里发生了什么。我做错了吗?

修改的 好的,我在实际代码中看到Key在其他方法和更改中被使用,因此它们会反映在hashCode中对象的HashMap中。这可能是这种行为的原因,它会丢失吗?

4 个答案:

答案 0 :(得分:4)

@Override equals/hashCode

的正确@Override

我不相信你hashCode/equals(你正在使用注释,对吧?)@Override。如果您未使用int hashcode(),则可能已定义boolean equals(Key)equals,但这些都不会执行所需的操作。


关键突变

如果你要改变地图的键,那么肯定会出现麻烦。来自the documentation

  

注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的关键字时,以影响Map<List<Integer>,String> map = new HashMap<List<Integer>,String>(); List<Integer> theOneKey = new ArrayList<Integer>(); map.put(theOneKey, "theOneValue"); System.out.println(map.containsKey(theOneKey)); // prints "true" theOneKey.add(42); System.out.println(map.containsKey(theOneKey)); // prints "false" 比较的方式更改对象的值,则不会指定地图的行为。

以下是一个例子:

cache

顺便说一下,在类型声明中更喜欢接口到实现类。以下是 Effective Java 2nd Edition的引用:第52项:通过接口引用对象

  

[...]你应该倾向于使用接口而不是类来引用对象。 如果存在适当的接口类型,则应使用接口类型声明参数,返回值,变量和字段。

在这种情况下,如果可能的话,您应该将Map简称为HashMap而不是{{1}}。

答案 1 :(得分:0)

我建议对equals和hashCode方法进行双重和三重检查。请注意,它是hashCode,而不是hashcode。

答案 2 :(得分:0)

查看(抽象的)代码,一切似乎都是有序的。可能是实际代码与编辑版本不同,这更多地反映了您对代码的工作方式,而不是实践中发生的情况!

如果您可以发布代码,请执行此操作。与此同时,这里有一些尝试:

  • 添加密钥后,再次使用完全相同的密钥实例,并验证它是否产生缓存命中。
  • 在测试中,验证哈希码是否相等,以及对象是否相等。
  • Map实现真的是HashMap吗?一旦密钥不再可访问,WeakHashMap将以您描述的方式运行。

答案 3 :(得分:0)

我不确定你的Key课程是什么,但是(抽象地类似于你)我做的简单检查是:

Key k1 = new Key();
Key k2 = new Key();
System.out.println("k1 hash:" + k1.hashcode);
System.out.println("k2 hash:" + k2.hashcode);
System.out.println("ks equal:" + k1.equals(k2));
getValue(k1);
getValue(k2);

如果代码显示异常 - 相同的哈希码,相同的密钥,但尚未缓存 - 那么会引起担心(或者更好的是,调试您的{ {1}}类;-)。您使用新的Key进行测试的方式可能会生成不一定表现相同的键。