美文网首页
提示十一

提示十一

作者: 飞絮搅青冥 | 来源:发表于2022-05-18 22:50 被阅读0次

    今天来看提示十一: 覆盖 equals 方法时总要覆盖hashCode 方法。

    如果不这样做,你的类违反了 hashCode 的通用约定,这会阻止它在 HashMap 和 HashSet 这样的集合中正常工作。

    1. 程序执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么多次调用hashCode方法都必须始终如一地返回同一个整数。

    2. 如果两个对象根据equals比较相等,那么hashCode结果应该相同。

    3. 如果两个对象使用equals比较必相等,则hashcode不一定要得到不一样的结果。但是如果结果不同可以调高散列表的性能。

    hashcode的返回值是一个Int,所以它最大的覆盖范围也就2^32,需要我们合理安排计算函数,让值域能够尽可能离散,提高相关性能。书中举了一个反例那就是不管什么情况,hashCode都返回42,这样也能满足上面的3点要求,但是会导致所有对象的哈希值都一样,哈希表退化为链表会退化成链表。

    书中还给出了一种简单合理的hashCode实现方法:

    1. 如果是基本数据类型,则可以调用对用类型的Type.hashCode(f)方法。

    2. 如果是一个对象引用,则应该调用该对象的hashcode方法。

    3. 如果是一个数组,则需要把每一个元素单独处理。如果有些元素重要,有些不重要,可以只挑出来重要的元素。

    4. 最后把所有元素的hash结果按照公式加总: resuot = 31 * result + c

    之所以用31去乘,一是他是个奇素数,另一个是jvm会用移位和减法来获取更好的性能 31 * i ==(i << 5) - i。另外书中也介绍了其他两种比较常见的计算方法:

    1. com.google.common.hash.Hashing,这个是google的Guava提供的方法,它尽量保证了不会出现哈希冲突。
    2. Objects.hashcode,它是JDK官方 提供的hash计算方法。缺点是因为它要创建数组,在速度上会慢一些。

    我也看过org.apache.commons.lang.builder.HashCodeBuilderapach提供的方法,也是一种不错的实现,是把重要的属性都放进去的builder模式,方便快捷。

    另外如果一个类是不可变的,并且计算哈希码的代价很大,那么可以考虑在对象中缓存哈希码,而不是在每次请求时重新计算哈希码。String类里面就是这样做的。但是书中也说了String类和Integer将 hashCode 方法返回的确切值指定为实例值的函数,这样不是一种好的做法,妨碍了在未来版本中改进哈希函数的能力。

    相关文章

      网友评论

          本文标题:提示十一

          本文链接:https://www.haomeiwen.com/subject/hbczurtx.html