重写 equals 方法时同时也要重写 hashcode 方法

在每个类中,在重写 equals 方法的时侯,一定要重写 hashcode 方法。 如果不这样做,你的类违
反了 hashCode 的通用约定,这会阻止它在 HashMap HashSet 这样的集合中正常工作。根据 Object
范,以下时具体约定。
1. 如果没有修改 equals 方法中用以比较的信息,在应用程序的一次执行过程中对一个对象重复调用
hashCode 方法时,它必须始终返回相同的值。在应用程序的多次执行过程中,每个执行过程在该
对象上获取的结果值可以不相同。
2. 如果两个对象根据 equals(Object) 方法比较是相等的,那么在两个对象上调用 hashCode 就必须产
生的结果是相同的整数。
3. 如果两个对象根据 equals(Object) 方法比较并不相等,则不要求在每个对象上调用 hashCode 都必
须产生不同的结果。 但是,程序员应该意识到,为不相等的对象生成不同的结果可能会提高散列
表(hash tables)的性能。
当无法重写 hashCode 时,所违反第二个关键条款是:相等的对象必须具有相等的哈希码( hash
codes)。 根据类的 equals 方法,两个不同的实例可能在逻辑上是相同的,但是对于 Object 类的
hashCode 方法,它们只是两个没有什么共同之处的对象。因此, Object 类的 hashCode 方法返回两个
看似随机的数字,而不是按约定要求的两个相等的数字
当无法重写 hashCode 时,所违反第二个关键条款是:相等的对象必须具有相等的哈希码
一个好的 hash 方法趋向于为不相等的实例生成不相等的哈希码。这也正是 hashCode 约定中第三条
的表达。理想情况下,hash 方法为集合中不相等的实例均匀地分配 int 范围内的哈希码。实现这种理想
情况可能是困难的。 幸运的是,要获得一个合理的近似的方式并不难。 以下是一个简单的配方:
1. 声明一个 int 类型的变量 result,并将其初始化为对象中第一个重要属性 c 的哈希码,如下面步
2.a 中所计算的那样。(回顾条目 10,重要的属性是影响比较相等的领域。)
2. 对于对象中剩余的重要属性 f ,请执行以下操作:
a. 比较属性 f 与属性 c int 类型的哈希码:
-- i. 如果这个属性是基本类型的,使用 Type.hashCode(f) 方法计算,其中 Type 类是对
应属性 f 基本类型的包装类。
-- ii. 如果该属性是一个对象引用,并且该类的 equals 方法通过递归调用 equals 来比较该属性,
并递归地调用 hashCode 方法。 如果需要更复杂的比较,则计算此字段的范式(“canonical
representation,并在范式上调用 hashCode。 如果该字段的值为空,则使用 0(也可以使用其
他常数,但通常来使用 0 表示)。
-- iii. 如果属性 f 是一个数组,把它看作每个重要的元素都是一个独立的属性。 也就是说,通
过递归地应用这些规则计算每个重要元素的哈希码,并且将每个步骤 2.b 的值合并。 如果数组没
有重要的元素,则使用一个常量,最好不要为 0。如果所有元素都很重要,则使用
Arrays.hashCode 方法。
b. 将步骤 2.a 中属性 c 计算出的哈希码合并为如下结果: result = 31 * result + c;
3. 返回 result 值。



posted @ 2020-03-28 22:12  webzom  阅读(224)  评论(0)    收藏  举报