我正在为java中的哈希映射构建一个复合键,并希望为每个这些对象确定自己的哈希码。我的问题是下面两者的最佳方法是什么。我的复合键有三个String属性和一个int属性。
public int hashCode(){
return (className + methodName + uniqueNumber).hashCode();
}
public int hashCode(){
return (className + methodName + desc + uniqueNumber).hashCode();
}
我必须拥有className,methodName和唯一编号,以保证每个密钥都有唯一的哈希码。我想采用最少发生碰撞的方法。我的直觉是,我“添加”到我的哈希映射函数的属性越多,发生冲突的可能性就越小。但是,我并不完全确定这是正确的。
答案 0 :(得分:2)
您的问题有点不清楚,您需要/哪些字段足以唯一区分密钥。
通常,您应该通过乘以素因子来组合各个哈希值(在复合键内)。
假设第一个例子:
public int hashCode() {
int h = className.hashCode() * 23;
h += methodName.hashCode() * 17;
h += uniqueNumber;
return h;
}
OTOH如果uniqueNumber
实际上是唯一的,您可以简化:
public int hashCode() {return uniqueNumber;}
在你的评论中你提到了一件事:“仅使用uniqueNumber将生成一个唯一的哈希值,但我将失去在hashmap中引用特定值的能力”。
现在这非常重要:“实例身份”是一个非常不同的东西哈希&查找,来自“价值”!你不能使用相同的哈希码&两者的地图。
例如,如果您需要一个Key(ClassName,MethodName) - > SomeValue查找将是一个“值”查找&需要通过ClassName&进行哈希处理MethodName值,以便可以重复:即,您可以为Map.get()构造一个键来执行查找。
“实例标识”实际上内置了对哈希和&amp ;;的支持。 Java中的地图 - 它叫做IdentityHashMap。
但对于大多数情况,包括&尤其是可能用于地图的复合键,需要能够重新构造密钥以便稍后执行查找。因此密钥应该具有值语义,并且您的uniqueNumber
是否应该实际上是密钥的一部分是不确定的。
当您稍后进行查找时,如何获得正确的uniqueNumber
来检索数据?我的感觉是:
要么应该有一个第一类实体,你可以直接使用它作为键(所以不再需要CompositeKey类),或
您无法重复获取uniqueNumber
,在这种情况下它无效/无论如何都不需要。
总结一下:如果uniqueNumber
真的需要或适用,我希望它已经封装在一流的实体中。事实并非如此。看起来你应该最好使用基于值的键,并删除uniqueNumber位(至少从这里开始)。
所以我的建议:
public int hashCode() {
int h = className.hashCode() * 23;
h += methodName.hashCode() * 17;
h += desc.hashCode();
return h;
}
如果这有帮助,请告诉我。
答案 1 :(得分:0)
一些评论;
(1)哈希码不必是唯一的。事实上,他们通常不保证是独一无二的。在大多数情况下,保证唯一性的计算成本太高,也不是理想的。碰撞不是灾难性的。
(2)散列码应该反映对象实例的状态,而不是对象类。类名这样的东西不会进入它。当然,除非IS是类的实例数据,例如在表示堆栈跟踪的一帧的类中,否则可能。
(3)良好的哈希码将具有大量可能的值,并且这些值将以概率方式分布,以使冲突不可能。
(4)在Java中,哈希码必须与Object.equals()
一致。请参阅Javadoc以获取java.lang.Object
以供参考。