覆写hashCode

作者: sunxiaohang | 来源:发表于2017-03-24 09:36 被阅读55次

    在比较两个实例是否相等的时候,通常会覆写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

    相关文章

      网友评论

        本文标题:覆写hashCode

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