HashMap碰撞:我的代码是否正确?

时间:2010-11-15 19:22:59

标签: java hashmap key hash-collision

我希望有一个DateWrapper - 代表一个日期(为Hibernate持久性而构建,但这是另一个故事) - 最多同时出现在同一个日期。

我对碰撞和哈希的好键有点困惑。我正在为DateWrapper对象编写工厂,我想用解析日期的毫秒作为关键,就像我见过其他人一样。 但是,如果发生碰撞会发生什么?。毫秒总是彼此不同,但内部表可能小于可能存在的Long。一旦哈希映射发生冲突,它就会使用等号,但是如何区分两个不同的对象?也许,这是put方法来删除(覆盖)我要插入的一些值... 那么,这段代码是安全的,还是被窃听?

package myproject.test;

import java.util.HashMap;
import java.util.Map;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import myproject.utilities.DateWrapper;

public class DateWrapperFactory {

    static Map <Long, DateWrapper> cache = new HashMap<Long, DateWrapper>();
    static DateTimeFormatter parser =
        DateTimeFormat.forPattern("yyyy-MM-dd");

    static DateWrapperFactory instance = new DateWrapperFactory();

    private DateWrapperFactory() {
    }

    public static DateWrapperFactory getInstance() {
        return instance;
    }


    public static DateWrapper get(String source) {
        DateTime d = parser.parseDateTime(source);
        DateWrapper dw = cache.get(d.getMillis());
        if (dw != null) {
            return dw;
        } else {
            dw = new DateWrapper(d);
            cache.put(d.getMillis(), dw);
            return dw;
        }
    }

}

package myproject.test;

import org.joda.time.DateTime;

public class DateWrapper {

    private DateTime date;

    public DateWrapper(DateTime dt) {
        this.date = dt;
    }

}

4 个答案:

答案 0 :(得分:0)

使用HashMap,您只能在任何给定的键值下存储一个条目(例如,在您的情况下为Long)。

另外,如果有任何并发​​机会,您可能希望使用ConcurrentHashMap和putIfAbsent()而不是非原子get / if / put调用。

答案 1 :(得分:0)

将在Long键上调用equals(),而不是值。你很好。

答案 2 :(得分:0)

如果您正在使用您想要的实际对象作为映射键,并让HashMap处理它对这些对象的哈希码所做的详细信息(并且键实现equals和{ {1}}根据他们的合同)如果有一个哈希码冲突而不是一些可能的性能降低将是没有问题的,因为需要线性搜索散列到同一个桶的每个条目。

在你的另一个问题中出现碰撞主题的问题是,不是使用应该是关键字的实际对象,而是使用该对象的哈希码作为密钥本身。这是不正确的,并且会导致不正确的行为....当你去查找地图中给定键的值时,结果可能是实际映射到恰好有一个完全不同的键的值相同的哈希码。

故事的寓意是:使用实际密钥或绝对等同的东西(例如本例中hashCode的毫秒)作为密钥,而不是密钥的哈希码。 DateTime为您完成了哈希码所需的功能。

答案 3 :(得分:0)

考虑到你最终要用这个来完成的事情,这似乎并不是非常有效。您拥有高度优化的数据结构,专门用于快速搜索和实施唯一性,称为数据库索引。 Hibernate为您提供了非常强大的内存和L2缓存功能。顺便提一下,没有将HashMap放在静态字段上的线程安全问题。

为什么不将数字作为数据库中ID列的值,让强大的平台技术快速找到并为您缓存?内存中的L2缓存命中实际上并不比宏观方案中的HashMap慢得多。这将是一个非常罕见的应用程序,其中差异是您有意义的热点之一。