资讯专栏INFORMATION COLUMN

覆写hashCode

xcc3641 / 2684人阅读

摘要:如果调用父类的方法,且返回值是返回的值却不同,因此在覆写方法的同时覆写方法。这样才能最大限度地保证,在程序运行过程中尽可能少的出现莫名其妙的错误。

在比较两个实例是否相等的时候,通常会覆写equal()方法,然后对类对象的每一成员进行逐一比较,但是JavaSE6规范如下:

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

如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

如果调用父类的equal()方法,且x.equal(y)返回值是true,返回的hashCode值却不同,因此在覆写equal()方法的同时覆写hashCode()方法。这样才能最大限度地保证,在程序运行过程中尽可能少的出现莫名其妙的错误。

再此之前我们先看一下String类中的hashCode()方法:

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

大家可能会觉得莫名其妙,hashCode()方法返回的是一个int类型的值,难道这就是所谓的hashCode?不要急,我们来看一段话,

一个好的散列函数通常倾向于“为不相等的对象产生不相等的散列码”
对于对象中的每个关键域f(指equal方法中涉及的每个域),完成以下步骤:

如果该域是boolean类型,则计算(f?1:0);

如果该域是byte、char、short或者int计算(int)f;

如果该域是long型,计算(int)(f^(f>>>32));

如果该域是float类型,计算Float.floatTOIntBits(f);

如果该域是double类型,计算Double.doubleToLongBits(f),然后再根据long型计算得到散列值;

如果该域是一个引用对象,并且该类的equal方法通过递归调用equal的方法来比较这个域,则同样为这个域递归调用hashCode,如果这个域为空,则返回0;
-如果该域是一个数组,则要把每一个元素当作多带带的域来处理

按照下面的公式,把上面计算得到的散列码c合并到result中

result=31*result+c;

--------------摘自Effective Java

这是EffectiveJava中给出的计算散列码的方法,当然,方法并不是唯一,只要我们保证相同的对象会产生相同的散列码,不同的获得的散列码不同就可以了。

现在我们回过头来看看String类中的hashCode方法

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {//判断hash值不为0,字符串不为空(即长度大于0)
            char val[] = value;//将字符串的值转化为char型数组
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];//遍历char数组中的每一个元素通过计算得到hash值
            }
            hash = h;
        }
        return h;
    }

看到这里相信大家已经明了,hash散列码的意义所在,
这里我们给出一段三个域都是int的hash值计算实例

    @Override
    public int hashCode() {
        int result = hashCode;
        //生成对象的唯一散列码
        if (result == 0) {
            result = result * 31 + areaCode;
            result = result * 31 + prefix;
            result = result * 31 + lineNumber;
            hashCode=result;
        }
        return hashCode;
    }

最后,如果大家想深入学习java的话,建议大家看一看effective java,相信会收获颇丰的。

更多关于java的文章请戳这里:(您的留言意见是对我最大的支持)

我的文章列表

Email:sxh13208803520@gmail.com

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66959.html

相关文章

  • 13.java object类

    摘要:常用方法取的对象信息类的方法返回一个字符串,该字符串由类名对象是该类的一个实例标记符和此对象哈希码的无符号十六进制表示组成。方法返回的运行时类类型。至于同一个应用程序在不同执行期所得的调用结果,无需一致。 概念 object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来. 在定义一个类时,如果没有明确的继承一个父类的话,那么它继承的就...

    wind3110991 评论0 收藏0
  • 【算】从散列表到HashMap

    数组 数组是我们比较熟悉的一种数据结构:固定大小,索引(下标)对应的槽位用以存储数据: showImg(https://segmentfault.com/img/bV7rJ8?w=480&h=119); 我们要在数组中查找一个值,比如红框圈中的 元素5 ,可以通过遍历或者排序后二分的方式达到目的。没有更快捷的查找方式了吗?显然是有的,比如Map。我们对存 / 取动一动脑筋,还是上图的那些元素,假如...

    zoomdong 评论0 收藏0
  • LinkedHashMap 源码详细分析(JDK1.8)

    摘要:关于的源码分析,本文并不打算展开讲了。大家可以参考我之前的一篇文章源码详细分析。在删除节点时,父类的删除逻辑并不会修复所维护的双向链表,这不是它的职责。在节分析链表建立过程时,我故意忽略了部分源码分析。 1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题。除此...

    Harriet666 评论0 收藏0
  • Java 8 新特性之默认方法(Default Methods)

    摘要:概述引入了新的语言特性默认方法。覆写默认方法,这跟类与类之间的覆写规则相类似。静态默认方法的另一个特性是接口可以声明并且可以提供实现静态方法本文首发于凌风博客新特性之默认方法作者凌风 1. 概述 Java 8 引入了新的语言特性——默认方法(Default Methods)。 默认方法允许您添加新的功能到现有库的接口中,并能确保与采用旧版本接口编写的代码的二进制兼容性。 1.1 为什么...

    QLQ 评论0 收藏0
  • 解读 Java 8 HashMap

    摘要:在二叉查找树强制一般要求以外,对于任何有效的红黑树增加了如下的额外要求节点是红色或黑色。红黑树有哪些应用场景内核和系统调用实现中使用的完全公平调度程序使用红黑树。 前言 这篇文章是记录自己分析 Java 8 的 HashMap 源码时遇到的疑问和总结,在分析的过程中笔者把遇到的问题都记录下来,然后逐一击破,如果有错误的地方,希望读者可以指正,笔者感激不尽。 疑问与解答 什么是 initia...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

xcc3641

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<