美文网首页
HashCode的深思

HashCode的深思

作者: Magic旭 | 来源:发表于2019-11-12 10:51 被阅读0次

    hash值计算方法深思

    1. 项目中用到了RecyclerView的DiffUtil,其中就涉及到equals来判断两个类变量是否相同,散列结构存储又涉及到了Hash值计算。其中hashCode方法内部如何实现自己定义的hash值。当散列结构存储存储对象时,难免会遇到A与B对象的hash值相同的时候,hash值相同后用equals方法去判断是否是为同一个变量,如果equals返回true,则代表散列结构存储中已经有该对象,所以会舍弃掉;如果equals返回false,则将该对象添加进散列结构存储中。

    hashCode与equals的关系

    1. hashCode相同的情况下,equals不一定返回true。(例如A与B发生hash碰撞,但他们是两者完全不同的对象)。
    2. 两个对象equals返回true的时候,则hashCode必须返回相同的int值。
    3. 两个对象hashCode返回不同的int值,equals一定会返回false。
      参考文献

    String

    hasCode方法
    1. 为了方便理解hashCode的计算,我们下面用从String源码分析一波。
      首先我们先看一眼源码,再后面一点点进行分析。
    public int hashCode() {
            //hash初始化是0
            int h = hash;
            final int len = length();
            if (h == 0 && len > 0) {
                for (int i = 0; i < len; i++) {
                    h = 31 * h + charAt(i);
                }
                hash = h;
            }
            return h;
    }
    
    1. 上面hash值的计算中为什么我们要选择31作为因子进行计算呢?原因选择数字31是因为它是一个奇质数,如果选择一个偶数会在乘法运算中产生溢出,导致数值信息丢失,因为乘二相当于移位运算。选择质数的优势并不是特别的明显,但这是一个传统。同时,数字31有一个很好的特性,即乘法运算可以被移位和减法运算取代,来获取更好的性能:31 * i == (i << 5) - i,现代的 Java 虚拟机可以自动的完成这个优化。
      这里参考文献:为什么选择31
    2. 看完文献可以发现,选择31是尽可能避免在散列存储中计算hash值发生hash碰撞,假如很不幸发生了hash碰撞那又该如何判断String是否完全相同呢?那就要看接下来介绍的equals方法了。
    equals方法
    1. 可以从String方法中观察到,是否需要往常量池需要添加新的String,hashCode与equals都是必不可少的,其中当两个不同的String的hashCode返回值相同时,会用比较传统且安全的方法对比两个对象是否完全相同。这个传统的方法就是逐个比较每个字符是否相同,如果遇到一个不同立即返回false。
    public boolean equals(Object anObject) {
            if (this == anObject) {
                //如果比较的对象是当前对象
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String) anObject;
                int n = length();
                if (n == anotherString.length()) {
                    int i = 0;
                    while (n-- != 0) {
                        if (charAt(i) != anotherString.charAt(i))
                                return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    

    总结

    1. 学无止境,抽空去学习自己感兴趣的Android源码的知识,一点一滴学习,你会发现在需要用到的时候,你能把很多知识点给串联起来,这才是成长的关键。

    相关文章

      网友评论

          本文标题:HashCode的深思

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