在密码学中,哈希算法有 MD5 SHA1 SHA256 等。现在对两个数据的二进制内容分别做哈希运算,如果哈希值不同,那么这两个数据的二进制内容一定不同,而如果哈希值相同,这两个数据的二进制内容可能相同,也可能不同,这时就需要逐个比特位的比较两个数据的内容,才能最终确认内容是否相同。
在 Java 中,那两个数据就好比是两个对象,hashCode() 就好比是密码学中的哈希运算结果,逐个比特位比对两个数据内容是否相同,就好比是 equals() 的计算过程。
当通过 HashSet 的 contains() 方法判断集合是否包含某个对象时,首先会计算该对象的 hashCode() 找到对应的 bucket,如果对应的 bucket 是空的,那么一定不包含该对象,如果不是空的,就需要进一步通过 equals() 方法判断对象是否确实存在。
言归正传,Java 中 equals() 代表 逻辑相等,hashCode() 计算的散列值用于确定散列表中的位置,便于快速查询。
equals hashCode 都属于 Object 类,如果要覆盖,必须遵守相应的约定,否则依赖这些约定的类,例如 HashMap HashSet 就无法结合该类一起正常运作。
equals 的约定如下:
- 自反性
- 对称性
- 传递性
- 一致性
hashCode 的约定如下:
- 在应用程序的执行期间,只要对象的
equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个证书。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。 - 如果两个对象根据
equals方法比较是相等的,那么调用者两个对象中任意一个对象的hashCode方法都必须产生相同的整数结果。 - 如果两个对象根据
equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的证书结果,有可能提高散列表的性能。
Effective Java 提到,覆盖 equals 时总要覆盖 hashCode