为什么java中的默认hashcode()不好?

时间:2013-04-12 18:05:52

标签: java hash hashcode

如果我没记错的话,在Object()类型的对象的java中默认的hashCode()实现是返回对象的内存地址。当我们创建自己的类时,我读到我们想要覆盖hashCode(),这样当我们将它们插入到哈希相关的集合(如HashMap())时,它将正常工作。但为什么内存地址不好?

当然,我们将永远耗尽内存而你会发生冲突,但我认为这是一个问题的唯一情况是你处理大量数据并且内存很少,然后它会开始影响性能,因为java中的哈希相关集合通过链接解决冲突(存储桶将链接到解析为相同哈希码/索引的值列表)。

4 个答案:

答案 0 :(得分:24)

如果每个对象都是唯一的,则默认实现可以正常工作。但是如果你重写equals(),那么你隐含地说具有不同地址的对象可以彼此相同。在这种情况下,您还必须覆盖hashCode()。

想想String类。

String s1 = new String("foo");
String s2 = new String("foo");

这两个字符串相等,因此它们的哈希码必须相等。但它们是具有不同地址的不同对象。

s1 == s2         // false, different addresses
s1.equals(s2)    // true, same contents

将他们的地址用作哈希码将是一个错误。因此,String会覆盖hashCode()以确保相等的字符串具有相同的哈希码。这有助于满足hashCode()的合同,即:

  

如果a.equals(b)为真,那么a.hashCode() == b.hashCode()

底线:如果覆盖equals(),还会覆盖hashCode()。

答案 1 :(得分:1)

将对象放入hashmap时使用的确切键对象可能无法在程序中访问该映射。所以你最终将覆盖equals方法。当您重写equals方法时,请确保它们的哈希码也相等,否则您无法从哈希映射中检索对象。

答案 2 :(得分:0)

虽然您不使用equals方法,但可以不定义hashCode,但在hashCode的合同为对象提供相同的结果之后,等于。你不能确定它会,所以你需要自己重写

hashCode

答案 3 :(得分:0)

决定数据结构应该使用哪个hashCode()实现隐式地是hashmap API的一部分。

为某些API提供未经您严格处理的信息,将控件从您手中夺走。

使用默认的hashCode()实现将您希望管理的密钥耦合到内存地址,这不是您处理的,而您不是对...有任何控制。

假设有一天你会想要使用某个内存优化器,它会在内存周围移动对象以保持一致性和更好的性能。 您将无法再使用您的数据结构,因为它保存了您的密钥的原始哈希地址。

从更实际的角度来看,

为了在整个程序中从数据结构中检索值,您必须保留对先前插入的所有键的引用(通过使用其他数据结构)。 您将无法使用在对象状态方面“相似”的键。

Person steve1 = new Person("Steve","21","engineer");
Person steve2 = new Person("Steve","21","engineer");

map.put(steve1,"great worker");

map.get(steve2); 
// returns null because "steve2" is not considered a key like "steve1"

map.get(steve1); 
// returns "great worker"