HashMap笔记

HashMap笔记

  1. 哈希表/散列表 的底层是Node类型的数组。
    Node节点存储hash、键、值与指针,方便形成链表/红黑树。

    transient Node<K,V>[] table;
    
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
        ...
    }
    
  2. 确定哈希桶数组索引的位置:

    1. 计算哈希值:
      将key的hashCode的高16位保留,低16位用原高16为与原低16位进行二次哈希,防止hashCode不合理而导致分布不均匀。
      例如:

      static final int hash(Object key) {
      	int h;
      	return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
      }
      
    2. 计算索引位置
      为了将hash值分配到哈希桶中,且保证不越界,我们应该对hash值取模,此处使用了位运算进行模运算(前提是哈希桶的数目,即table数组长度必须是 2n

      //其中(n - 1) & hash  =  n % hash
       final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
      	...
      	p = tab[i = (n - 1) & hash]
      	...
      }
      

      数组索引

  3. 哈希冲突的解决方法:拉链法
    如果计算得到的hash索引相同,则出现哈希冲突,HashMap利用拉链法解决冲突,即将同一个哈希桶内的元素用链表连起来;当当前桶内的元素过多(链表长度大于8)时,会将链表转换为红黑树,从而将在同一桶内遍历查找元素的时间复杂度从O(n)降低为O(logn)

  4. 扩容机制:

    1. 扩容条件:HashMap不会等到容量用完之后才会扩容,而会在达到阈值时就开始扩容。其中阈值取决于负载因子LoadFactor(默认0.75f)与容量Capacity的乘积。
    2. 扩容方法:创建一个容量为原容量oldCapacity 2倍的新数组,并将原数组中的元素重新Hash并放入新的桶中。重新Hash的过程即原来的通过位运算取模的过程,由于容量始终是2n, 所以在扩容(扩大两倍为2n+1)后,新计算的hash与旧值只可能在第n位有区别。如果第n位为0,则仍在原来位置的桶中,否则在原位置 + oldCap的桶中。
      在这里插入图片描述
      在这里插入图片描述
  5. HashMap的容量必须是2的整数次幂
    1.因为在计算哈希桶数组索引时,我们使用位运算来进行计算,只有 2n 才有 2n-1 的后 n 位全为1的特性,从而用位运算代替取模。
    2.在扩容时,计算新的hash值时,仅需要查看原来的hash值新增的第n位bit是0还是1,省去了重新计算hash值的时间,而且同时,由于新增的1bit是0还是1可以认为是随机的,因此resize的过程,均匀的把之前的冲突的节点分散到新的bucket了。

  6. HashMap增加新元素的步骤
    1.首先根据key值,通过哈希算法得到value应该放在底层数组中的下标位置。
    2.根据这个下标定位到底层数组中的元素,当然,这里可能是链表,也可能是树。
    3.拿到当前位置上的key值,与要放入的key比较,是否 == 或者equals,如果成立的话就替换value值,并且需要返回原来的值。
    4.如果是树的话就要便利中的节点,继续==和equals的判断,成立替换,否则添加到树里
    5.链表的话需要遍历链表,同样的判断,成立。替换,否则就添加到链表的尾部

参考链接:

  1. 【java】HashMap 一遍就懂!!!!
    首发为美团技术团队: Java 8系列之重新认识HashMap
  2. 害怕面试被问HashMap?这一篇就搞定了!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值