我希望有一个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;
}
}
答案 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慢得多。这将是一个非常罕见的应用程序,其中差异是您有意义的热点之一。