6

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

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

4

4 回答 4

30

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

于 2013-04-12T18:08:40.457 回答
1

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

于 2014-04-01T13:58:55.510 回答
0

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

哈希码

于 2013-04-12T18:07:59.830 回答
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"
于 2016-02-26T09:07:19.880 回答