最近我读了这篇文章 开发人员工作文件。

该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。

我如何决定有效地实现这些方法?


当前回答

加上@Lombo的答案

什么时候需要重写equals() ?

Object的equals()的默认实现是

public boolean equals(Object obj) {
        return (this == obj);
}

这意味着两个对象将被认为是相等的,只有当他们有相同的内存地址,这将是真的,只有当你是 比较对象本身。

但是,如果两个对象对一个对象具有相同的值,则可能认为它们是相同的 或更多的属性(参考@Lombo的回答中给出的例子)。

所以在这些情况下,你会重写equals()你会给出你自己的相等条件。

我已经成功地实现了equals(),它工作得很好。那么为什么他们要求重写hashCode()呢?

好。只要不在用户定义的类上使用基于“Hash”的集合,就没问题。 但是在将来的某个时候,你可能想要使用HashMap或HashSet,如果你没有覆盖和“正确实现”hashCode(),这些基于Hash的集合将无法正常工作。

只覆盖等于(除了@Lombo的答案)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

首先,HashMap检查second的hashCode是否与First相同。 只有当值相同时,它才会继续检查同一桶中的相等性。

但这里这两个对象的hashCode是不同的(因为它们具有不同的内存地址-与默认实现不同)。 因此,它甚至不会关心是否相等。

如果在重写的equals()方法中有断点,那么如果它们有不同的hashcode,它就不会介入。 contains()检查hashCode(),只有当它们相同时才调用equals()方法。

为什么我们不能让HashMap检查所有桶是否相等呢?所以我没有必要重写hashCode() !!

那么你就错过了基于哈希的集合的要点。 考虑以下几点:

Your hashCode() implementation : intObject%9.

以下是以桶的形式存储的密钥。

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

假设,您想知道映射是否包含键10。 你想把所有的桶都搜一遍吗?或“是否只搜索一个桶?”

根据hashCode,可以确定如果存在10,则它必须存在于Bucket 1中。 所以只有桶1会被搜索!!

其他回答

为了在HashMap, Hashtable等集合中使用我们自己的类对象作为键。,我们应该通过了解集合的内部工作来重写这两个方法(hashCode()和equals())。否则,它会导致我们意想不到的错误结果。

hashCode ():

如果只重写hash-code方法,什么也不会发生,因为它总是为每个对象返回一个新的hashCode作为object类。

equals ():

如果你只覆盖equals方法,如果a.equals(b)为真,这意味着a和b的hashCode必须是相同的,但这不会发生,因为你没有覆盖hashCode方法。

注意:Object类的hashCode()方法总是为每个对象返回一个新的hashCode。

因此,当您需要在基于哈希的集合中使用对象时,必须重写equals()和hashCode()。

Java提出了一个规则

如果使用Object类的equals方法,两个对象相等,那么hashcode方法应该为这两个对象提供相同的值。

因此,如果在我们的类中重写equals(),我们也应该重写hashcode()方法来遵循此规则。 例如,equals()和hashcode()这两个方法都用于Hashtable中以键值对的形式存储值。如果我们覆盖其中一个而不是另一个,如果我们使用这样的对象作为键,哈希表可能不会像我们想要的那样工作。

加上@Lombo的答案

什么时候需要重写equals() ?

Object的equals()的默认实现是

public boolean equals(Object obj) {
        return (this == obj);
}

这意味着两个对象将被认为是相等的,只有当他们有相同的内存地址,这将是真的,只有当你是 比较对象本身。

但是,如果两个对象对一个对象具有相同的值,则可能认为它们是相同的 或更多的属性(参考@Lombo的回答中给出的例子)。

所以在这些情况下,你会重写equals()你会给出你自己的相等条件。

我已经成功地实现了equals(),它工作得很好。那么为什么他们要求重写hashCode()呢?

好。只要不在用户定义的类上使用基于“Hash”的集合,就没问题。 但是在将来的某个时候,你可能想要使用HashMap或HashSet,如果你没有覆盖和“正确实现”hashCode(),这些基于Hash的集合将无法正常工作。

只覆盖等于(除了@Lombo的答案)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

首先,HashMap检查second的hashCode是否与First相同。 只有当值相同时,它才会继续检查同一桶中的相等性。

但这里这两个对象的hashCode是不同的(因为它们具有不同的内存地址-与默认实现不同)。 因此,它甚至不会关心是否相等。

如果在重写的equals()方法中有断点,那么如果它们有不同的hashcode,它就不会介入。 contains()检查hashCode(),只有当它们相同时才调用equals()方法。

为什么我们不能让HashMap检查所有桶是否相等呢?所以我没有必要重写hashCode() !!

那么你就错过了基于哈希的集合的要点。 考虑以下几点:

Your hashCode() implementation : intObject%9.

以下是以桶的形式存储的密钥。

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

假设,您想知道映射是否包含键10。 你想把所有的桶都搜一遍吗?或“是否只搜索一个桶?”

根据hashCode,可以确定如果存在10,则它必须存在于Bucket 1中。 所以只有桶1会被搜索!!

因为如果你不重写它们,你将使用Object中的默认实现。

考虑到实例相等和hascode值通常需要了解组成对象的内容,它们通常需要在类中重新定义,以具有任何有形的意义。