覆盖等于而不是哈希码的缺点是什么,反之亦然?
what is the disadvantage of overriding equals and not hashcode and vice versa?
我知道那里有很多类似的问题,但我对阅读的答案并不满意。我试图弄清楚,但我仍然不明白。
我所知道的是,这两个在使用 set 或 map 时很重要,尤其是 HashSet、HashMap 或 Hash 对象,它们通常使用散列机制来存储元素对象。
这两种方法都是用来判断两个Object是否相等。
为了使两个对象 A 和 B 相等,首先它们需要具有相同的哈希值(必须在同一个桶中),其次我们必须在执行 A.equals(B).
时得到 true
我不明白的是,为什么有必要覆盖这两种方法。
如果我们不覆盖哈希码会怎样。是否必须覆盖 BOTH.If 这不是覆盖 equals 而不是 hashcode 的缺点,反之亦然。
是的,当您覆盖 equals 方法时,您也必须覆盖 hashcode 方法,这是正确的。背后的原因是,在散列基本元素中,如果两个对象的 equals 方法 return 为真且它们的 hashcode 方法 return 相同的整数值,则两个对象相等。在哈希基本元素(哈希映射)中,当您首先对两个对象进行相等检查时,将调用它们的哈希码方法,如果它 return 两者的值相同,则仅调用 equals 方法。如果 hashcode 没有 return 相同的值,那么它会简单地认为两个对象不相等。默认情况下,hashcode 方法 return 一些随机值,所以如果你通过覆盖 equals 方法使两个对象在某些特定条件下相等,它们仍然不会相等,因为它们的 hashcode 值不同,所以为了使它们hascode 值等于你必须覆盖它。否则您将无法将此对象作为哈希映射的键。
正确实施 hashCode
对于您的对象成为基于散列的容器中的键是必要的。其他的就没必要了。
这就是为什么它对基于散列的容器(例如 HashMap、HashSet、ConcurrentHashMap 等)很重要
在高层次上,HashMap 是一个数组,由键的 hashCode 索引,其条目是 "chains"-(键,值)对列表,其中特定链中的所有键都具有相同的哈希码。有关哈希表的复习,请参阅 Wikipedia.
考虑如果两个键 A、B 相等但具有不同的哈希码会发生什么 - 例如,a.hashCode() == 42
和 b.hashCode() == 37
。假设你写:
hashTable.put(a, "foo");
hashTable.get(b);
因为键是相等的,你希望结果是 "foo"
,对吧?
但是,get(b)
将查找对应于哈希 37 的链,而 (a, "foo")
对位于对应于哈希 42 的链中,因此查找将失败,您将得到 null
.
这就是为什么如果您打算将对象用作基于散列的容器中的键,则相同的对象具有相同的散列码很重要。
请注意,如果您使用非基于散列的容器,例如 TreeMap
,则您不必实施 hashCode
,因为容器不使用它。相反,在 TreeMap
的情况下,您应该实施 compareTo
- 其他类型的容器可能有自己的要求。
我知道那里有很多类似的问题,但我对阅读的答案并不满意。我试图弄清楚,但我仍然不明白。 我所知道的是,这两个在使用 set 或 map 时很重要,尤其是 HashSet、HashMap 或 Hash 对象,它们通常使用散列机制来存储元素对象。
这两种方法都是用来判断两个Object是否相等。 为了使两个对象 A 和 B 相等,首先它们需要具有相同的哈希值(必须在同一个桶中),其次我们必须在执行 A.equals(B).
时得到 true我不明白的是,为什么有必要覆盖这两种方法。 如果我们不覆盖哈希码会怎样。是否必须覆盖 BOTH.If 这不是覆盖 equals 而不是 hashcode 的缺点,反之亦然。
是的,当您覆盖 equals 方法时,您也必须覆盖 hashcode 方法,这是正确的。背后的原因是,在散列基本元素中,如果两个对象的 equals 方法 return 为真且它们的 hashcode 方法 return 相同的整数值,则两个对象相等。在哈希基本元素(哈希映射)中,当您首先对两个对象进行相等检查时,将调用它们的哈希码方法,如果它 return 两者的值相同,则仅调用 equals 方法。如果 hashcode 没有 return 相同的值,那么它会简单地认为两个对象不相等。默认情况下,hashcode 方法 return 一些随机值,所以如果你通过覆盖 equals 方法使两个对象在某些特定条件下相等,它们仍然不会相等,因为它们的 hashcode 值不同,所以为了使它们hascode 值等于你必须覆盖它。否则您将无法将此对象作为哈希映射的键。
正确实施 hashCode
对于您的对象成为基于散列的容器中的键是必要的。其他的就没必要了。
这就是为什么它对基于散列的容器(例如 HashMap、HashSet、ConcurrentHashMap 等)很重要
在高层次上,HashMap 是一个数组,由键的 hashCode 索引,其条目是 "chains"-(键,值)对列表,其中特定链中的所有键都具有相同的哈希码。有关哈希表的复习,请参阅 Wikipedia.
考虑如果两个键 A、B 相等但具有不同的哈希码会发生什么 - 例如,a.hashCode() == 42
和 b.hashCode() == 37
。假设你写:
hashTable.put(a, "foo");
hashTable.get(b);
因为键是相等的,你希望结果是 "foo"
,对吧?
但是,get(b)
将查找对应于哈希 37 的链,而 (a, "foo")
对位于对应于哈希 42 的链中,因此查找将失败,您将得到 null
.
这就是为什么如果您打算将对象用作基于散列的容器中的键,则相同的对象具有相同的散列码很重要。
请注意,如果您使用非基于散列的容器,例如 TreeMap
,则您不必实施 hashCode
,因为容器不使用它。相反,在 TreeMap
的情况下,您应该实施 compareTo
- 其他类型的容器可能有自己的要求。