HashMap关键问题 [英] HashMap key problems

查看:113
本文介绍了HashMap关键问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

缓存代码(有点抽象):

 静态HashMap<关键,价值> cache = new HashMap< Key,Value>(); 
$ b 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);
返回值;


$ / code $ / pre
$ b

分析代码:

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



$ b $ p $结果输出:

$ b pre> cache size = 0
没有缓存命中
(..)
缓存大小= 99
没有缓存命中

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

$ p $ new key()。hashcode == new Key()。hashcode // TRUE
new key()。equals(new Key())// TRUE

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



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



编辑
好​​的,我看到在实际代码中 Key 在其他方法和变化中使用,因此它们反映在 HashMap hashCode 中C $ C>。这可能是造成这种行为的原因,它会失踪吗?

正确 @Override

equals / hashCode



我不相信你 @Override (你正在使用注释,对吗?) hashCode / equals 正确。如果您没有使用 @Override ,您可能已经定义了 int hashcode() boolean equals(Key),这两者都不会做所需的事情。






On关键突变



如果您正在修改地图的键,那么会发生问题。从文档


注意:如果可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式进行更改,而对象是地图中的键,则不会指定地图的行为。


下面是一个例子:

  Map< List< ;整数>,字符串> map = 
new HashMap< List< Integer>,String>();
列表<整数> theOneKey = new ArrayList< Integer>();
map.put(theOneKey,theOneValue);

System.out.println(map.containsKey(theOneKey)); //打印true
theOneKey.add(42);
System.out.println(map.containsKey(theOneKey)); //打印false

顺便说一下,在类型声明中,接口更喜欢实现类。以下是来自 Effective Java 2nd Edition的一段引文:Item 52:通过它们的接口引用对象
$ b


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

在这种情况下,如果可能的话,应该将 cache 声明为 Map ,而不是 HashMap


I'm profiling some old java code and it appears that my caching of values using a static HashMap and a access method does not work.

Caching code (a bit abstracted):

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;
    }
}

Profiling code:

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

Result output:

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

It looked like a standard error in Key's hashing code or equals code. However:

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

What's especially weird is that cache.put(key, value) just adds another value to the hashmap, instead of replacing the current one.

So, I don't really get what's going on here. Am I doing something wrong?

edit Ok, I see that in the real code the Key gets used in other methods and changes, which therefore get's reflected in the hashCode of the object in the HashMap. Could that be the cause of this behaviour, that it goes missing?

解决方案

On a proper @Override of equals/hashCode

I'm not convinced that you @Override (you are using the annotation, right?) hashCode/equals properly. If you didn't use @Override, you may have defined int hashcode(), or boolean equals(Key), neither of which would do what is required.


On key mutation

If you are mutating the keys of the map, then yes, trouble will ensue. From the documentation:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

Here's an example:

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"

By the way, prefer interfaces to implementation classes in type declarations. Here's a quote from Effective Java 2nd Edition: Item 52: Refer objects by their interfaces

[...] you should favor the use of interfaces rather than classes to refer to objects. If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types.

In this case, if at all possible, you should declare cache as simply a Map instead of a HashMap.

这篇关于HashMap关键问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆