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

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

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

如果每个对象都是唯一的,则默认实现工作正常。 但是如果你重写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()。

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

虽然你不使用equals方法,但是没有定义hashCode ,但是在hashCode契约之后给对象提供相同的结果,那就等于。 你不能确定它会,所以你需要自己重写它

的hashCode

决定数据结构应该使用哪个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"