Hash算法以及java hashmap的源码分析

来源:互联网 发布:js鼠标移入事件 编辑:程序博客网 时间:2024/04/30 12:27

        hash算法也叫做散列函数,通过一个函数将任何信息转换成信息量的摘要。一个设计的比较好的hash算法,其冲突是比较少,冲突的含义就是不同的输入经过hash后得到了相同的摘要信息。

        这里我分析了一下java源代码中HashMap的实现。

static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }

        这里可以针对任何类型的对象进行hash计算,之所以传入的是int类型,那是因为java object类中hashcode()方法。该方法的定义也比较有意思。

public native int hashCode(); 说明该方法是c++实现的。因此肯定要加载对应的dll文件。但是这里并没有发现加载什么dll文件。看看java代码里面的加载吧。

private static native void registerNatives();    static {        registerNatives();    }
        我看到这里后,彻底晕倒了。我仅能得到的结论是:hashmap的实现中,java是将key值进行hashcode计算得到int类型,然后再hash计算得到摘要信息。看看hashmap的put方法吧。

 public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key.hashCode());        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }
        这里首先调用了hash(key.hashCode())对key值进行hash,得出的值到table中查询,table是存放所有的值的数组,该数组的包含的对象是Entry对象,这个对象就像链表里面的节点一样。具体可以看看代码了。

        然后对其hash值进行查找,并看table中该索引下的值是否为空,如果不为空的话,则在当前位置的元素中,建立一个链接,新建一个Entry对象,这样,在table数组当前的索引下,就是一个链表了。这是处理冲突的一种方法。如果table中该索引下的值是空的,说明使用正常,不存在冲突。

        需要注意下哦,这里hash出来的值比较大,但是如何把这么大的值直接映射到这么小的数组空间上来呢,在indexFor()方法里面有一些眉目可以看到

 static int indexFor(int h, int length) {        return h & (length-1);    }

        经过与计算后,再大的值都会在数组空间范围内了。

        关于java里面的hash就记录到这里了。

        以下有一篇翻译的文章对理解hash比较有帮助。而且记录有各种hash算法。摘录以下代码记录一下。

        http://blog.csdn.net/eaglex/article/details/6310727

 

package com.bplead.hash;public class Hash {public static long RSHash(String str){int b = 378551;int a = 63689;long hash = 0;for(int i=0;i<str.length();i++){hash = hash * a + str.charAt(i);a = a +b;}return hash;}public static long JSHash(String str){        long hash = 1315423911;        for(int i = 0; i < str.length(); i++)        {           hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));        }        return hash;  }  public long SDBMHash(String str){        long hash = 0;        for(int i = 0; i < str.length(); i++)        {           hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;        }        return hash;  }  public long DJBHash(String str){        long hash = 5381;        for(int i = 0; i < str.length(); i++)        {           hash = ((hash << 5) + hash) + str.charAt(i);        }        return hash;  }  public long DEKHash(String str){        long hash = str.length();        for(int i = 0; i < str.length(); i++)        {           hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);        }        return hash;     }  public static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }public static void main(String[] args) {String temp = "HelloWorld12";int index = hash(temp.hashCode());System.out.println(index);System.out.println(index&15);}}




原创粉丝点击