hashMap怎么保证hash一致性的

作者: 凯哥Java | 来源:发表于2018-07-24 14:16 被阅读0次

    http://kaigejava.com/article/detail/168

    学Java的都知道hashMap的底层是“链表散列”的数据结构也也可以说是hash表。在put的实话先根据key的hashcode重新计算hash值的,而我们又知道hash是一种算法。所以哈希码并不是完全唯一的。

    查看哈希码百科:

    哈希表可以说就是数组链表,底层还是数组但是这个数组每一项就是一个链表

    一:为什么说hashmap的put方法是根据key进行hashcode计算的呢?

    查看源码:

    在查看hash方法,如下:

    查看putVal方法:

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

    boolean evict) {

    Node [] tab; Node p; int n, i;

    if ((tab = table) == null || (n = tab.length) == 0)

    n = (tab = resize()).length;

    if ((p = tab[i = (n - 1) & hash]) == null)

    tab[i] = newNode(hash, key, value, null);

    else {

    Node e; K k;

    if (p.hash == hash &&

    ((k = p.key) == key || (key != null && key.equals(k))))

    e = p;

    else if (p instanceof TreeNode)

    e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value);

    else {

    for (int binCount = 0; ; ++binCount) {

    if ((e = p.next) == null) {

    p.next = newNode(hash, key, value, null);

    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

    treeifyBin(tab, hash);

    break;

    }

    if (e.hash == hash &&

    ((k = e.key) == key || (key != null && key.equals(k))))

    break;

    p = e;

    }

    }

    if (e != null) { // existing mapping for key

    V oldValue = e.value;

    if (!onlyIfAbsent || oldValue == null)

    e.value = value;

    afterNodeAccess(e);

    return oldValue;

    }

    }

    ++modCount;

    if (++size > threshold)

    resize();

    afterNodeInsertion(evict);

    return null;

    }

    二:hashmap怎么解决key的hash值冲突问题的?

    上图是源码截图,说明:

    1:初始化map的大小。默认是16

    示例代码:HashMap map = new HashMap();

    2:如果tab为空,就newNode一个放到链表中

    示例代码:map.put("aa",1); 也就是图-1测试代码中的1

    3:根据key算出的hash值如果存在,且key的值和map中已经存在的值equals了。所以就不处理。

    如下图:

    测试代码如图-1测试代码中的1和 2

    4:如果p是TreeNode的子类进行putTreeValu

    5:如果key的hash值和map中已经存在的key的hash相等且key不同的时候,如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

    如图-1测试代码 1和4中key的hesh值都为3104

    图-1测试代码

    在来看下Node这个内部类:

    三:在来看看怎么get方法

    说明:

    1:如果链表中第一个值的hash值和需要获取的key的hash值相等的话,就直接取出。

    2:如果链表first.next !=null就循环查找链表中的key,知道查询到key.equals(k) 取出对应的值。

    查看源码或许感觉不懂,那么画图来说明:

    总结:

    数据结构:哈希表可以说就是数组链表,底层还是数组但是这个数组每一项就是一个链表。

    map的put方法:

    1:new hashMap的时候初始化默认大小为16

    2:当map.put("aa",1)的时候判断map没有值,就把aa算的hash值放到0X004的位置

    3:当再次执行map.put("aa",1)的是计算aa的hash值为3104.此时在OX004的位置已经有数据了。进行判断存在的key和新put的key是否相同。相同不处理,值覆盖

    4:执行map.put("aa",2)的时候key和已经存在的key相同就直接覆盖value了

    5:执行map.put(3104,"cc")的时候,key的hash值也为3104.此时数组中OX004已经存在数据,判断key是否相同。发现3104和aa不相同【注:此时就发生了hash冲突】,那么就aa这个链表前面追加3104

    6:执行map.put("bb","cc")。假设bb计算出的hash值是3105就存放在了OX005上。

    其他依次类推

    map的get方法:

    当执行map.get("bb")的时候先计算出bb的hash值为3105在对应的位置(也就是0X005)取出第一个判断值是不是bb如果是就直接取出value.

    当执行map.get("aa")的时候先计算出aa的hash值为3104,去对应的位置取出判断值(3104)不等于(aa)且还有next。就循环取出进行比较。

    相关文章

      网友评论

        本文标题:hashMap怎么保证hash一致性的

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