对java的Hash方法的一些分析总结

来源:互联网 发布:烟台华商网络怎么样 编辑:程序博客网 时间:2024/04/30 05:22

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="font-size:18px;">本文大部分转自  http://www.cnblogs.com/tonyluis/p/5671873.html</span></span>

HashCode()方法是在java的Object类中定义的。

<span style="font-size:18px;">public native int hashCode(); </span>
从定义可以看出,hashCode()是一个本地方法(本地方法即不是用java的代码写的,是JVM调用其他的代码,如C/C++等),所以这个方法的实现不唯一,对于一些JVM,hashCode()返回的就是对象的地址,大多时候JVM根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,并返回。

HashMap中的put()方法如下:

<span style="font-size:18px;">public V put(K key, V value) {</span>
<span style="font-size:18px;">        if (key == null)</span>
<span style="font-size:18px;">            return putForNullKey(value);</span>
<span style="font-size:18px;">        int hash = hash(key.hashCode());  //求hashcode,但是hashcode过大,不能均匀散列,所以需要hash一下</span>
<span style="font-size:18px;">        int i = indexFor(hash, table.length);//table是一个数组,存储的对那是Entry,table.length默认为16,即4位,这里取后四位,作为关键字</span>
<span style="font-size:18px;">        for (Entry<K,V> e = table[i]; e != null; e = e.next) {</span>
<span style="font-size:18px;">            Object k;</span>
<span style="font-size:18px;">            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {</span>
<span style="font-size:18px;">                V oldValue = e.value;</span>
<span style="font-size:18px;">                e.value = value;</span>
<span style="font-size:18px;">                e.recordAccess(this);</span>
<span style="font-size:18px;">                return oldValue;</span>
<span style="font-size:18px;">            }</span>
<span style="font-size:18px;">        }</span>
<span style="font-size:18px;">          modCount++;</span>
<span style="font-size:18px;">        addEntry(hash, key, value, i);</span>
<span style="font-size:18px;">        return null;</span>
<span style="font-size:18px;">    }</span>
其中,indexFor函数为

<span style="font-size:18px;">static int indexFor(int h, int length) {  //取低位为table中的索引</span>
<span style="font-size:18px;">         return h & (length - 1);</span>
<span style="font-size:18px;">}</span>

因为hashMap要求Entry数组长度必须为2的幂(hashMap默认值为16,hashTable没有这个要求,默认值为11),所以上述代码就是取h的低4位作为Entry数组的下标。由于覆盖equals()需要覆盖hashCode(),所以hashCode()有时并不十分完美,比如只和高位有关等等,因此需要再次hash()一下。

JDK1.8中的hash()方法如下:

<span style="font-size:18px;">static final int hash(Object key) {</span>
<span style="font-size:18px;">int h;</span>
<span style="font-size:18px;">return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//>>>指的是无符号右移,高16位于低16位做异或</span>
<span style="font-size:18px;">}</span>
hash函数被称为扰动函数,右移16位,正好保证高半区和低半区做异或,从而混合了原来的哈希码的高位和低位,从而加大了低位的随机性,并且混合后,低位也包含了高位的信息,高位信息被变相保留下来,能够有效减小碰撞的次数。


0 0
原创粉丝点击