• HashMap的底层实现


    疫情原因,今年的五一没出去浪,在家没事,写个博客记录下Java中HashMap的put操作。

    当执行下面这段代码,put一个值的时候,流程是什么样的呢?

    HashMap<String, String> map = new HashMap<String, String>();
    map.put("姓名", "张三");
    //JDK源码
    public
    V put(K key, V value) { return putVal(hash(key), key, value, false, true); } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // 判断桶是否为空 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // (n - 1) & hash 计算下标,为空时直接放入 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> 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<K,V>)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; }

    以上是源码,下面引用一张图来理解下上面的代码中寻址的过程:

    1、首先会拿着key值,计算出hashcode值,h = key.hashCode()

    2、再将该值右移16位后与原值做异或操作,h ^ (h >>> 16),这个叫扰动函数,目的是让高低16位参与运算减少hash碰撞的几率。

    3、然后用 hashCode 和 n-1 做与运算,1.8之前是用 hashCode 对数组长度取模,1.8对算法进行了优化,这样做的效果和对 hashCode 取模是一样的,但是效率会比之前高很多。

     这样就找到了key要存放的位置,接下来就是把值放入相应的位置

    1、如果没碰撞直接放到bucket里;

    2、如果节点已经存在就替换old value;

    3、如果碰撞了,以链表的形式存在buckets后;

    4、如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;

    5、当bucket满了(超过load factor*current capacity)时,就要扩容

    扩容就是将原数组的长度扩大2倍,重新计算key的 index,重新放入新的buckets中。

     

  • 相关阅读:
    白书上的BellmanFord模板
    c#中的分部类和分部方法
    c#类
    浪潮gs开发平台学习平台快速开发入门
    c#学习积累
    自定义属性编辑器
    hibernate 中的hql,nativesql ,list(),iterate() 的使用规则
    c#继承
    浪潮gs中间件服务器,客户端,数据库sqlserver安装注意事项
    c#接口
  • 原文地址:https://www.cnblogs.com/handongxue/p/12819953.html
Copyright © 2020-2023  润新知