HashMap相关

HashMap实现原理

HashMap的put方法的具体流程

HashMap寻址算法

HashMap扩容机制

为何HashMap的数组长度一定是2的次幂

HashMap在1.7情况的多线程死循环问题

HashTable与HashMap

HashMap实现原理

  • 数据结构:底层使用hash表数据结构,数组链表或红黑树
  • 添加数据时,计算key的值确定元素在数组的下标
    • key相同则替换 不同则存入链表或红黑树
  • 获取数据通过key的hash计算数组下标获取元素

jdk1.7和jdk1.8的实现有什么区别?

        JDK1.8之前采用拉链法。数组加链表

        JDK1.8之后采用数组+链表+红黑树:链表长度大于8且数组长度大于64则会从链表转化为红黑树

HashMap的put方法的具体流程

1.判断键值对数组table是否为空或为null,否则执行resize0进行扩容(初始化)
2.根据键值key计算hash值得到数组索
3.判断tableil==null,条件成立,直接新建节点添加
4.如果tableli]==null,不成立
4.1判断tablei]的首个元素是否和key一样,如果相同直接覆盖value4.2 判断tableli 是否为treeNode,即tableil 是否是红黑树,如果是红黑树,则直接在树中插入键值对4.3遍历table们,链表的尾部插入数据,然后判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,遍历过程中若发现key已经存在直接覆盖value
5.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold(数组长度*0.75),如果超过,进行扩容

HashMap扩容机制

HashMap使用的是懒加载,构造完不进行put方法,HashMap不会初始化或扩容table

  •         在添加元素或初始化的时候需要调用resize方法进行扩容,第一次添加数据初始化数组长度为16,以后每次每次扩容都是达到了扩容闯值(数组长度*0.75)
  •         每次扩容的时候,都是扩容之前容量的2倍;
  •         扩容之后,会新创建一个数,需要把老数组中的数据挪动到新的数组中

        没有hash冲突的节点,则直接使用 e.hash & (newCap - 1)计算新数组的索引位置
        如果是红黑树,走红黑树的添加
        如果是链表,则需要遍历链表,可能需要拆分链表,判断(e.hash & oldCap)是否为0,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上

HashMap寻址方法

  • 计算对象的 hashCode0)
  • 再进行调用hash0方法进行二次哈希hashcode值右移16位再异或运算,让哈希分布更为均匀
  • 最后(capacity - 1)& hash 得到索引

为什么HashMap数组长度一定为2的幂次方

  1. 计算索引时效率更高:如果是2的n次幂可以使用位与运算代替取模
  2. 扩容时重新计算索引效率更高: hash &odCap==0的元素留在原来位置,否则新位置 = 旧位置 + oldCap 

多线程死循环问题

链表插入元素时,JDK7 使用头插法插入元素,但在多线程的环境下, 扩容时会造成环形链或数据丢失,出现死循环。

HashTable与HashMap

HashMap

底层由链表+数组+红黑树实现
可以存储null键和null值
线性不安全
初始容量为16,扩容每次都是2的n次幂
加载因子为0.75,当Map中元素总数超过Entry数组的0.75,触发扩容操作.
并发情况下,HashMap进行put操作会引起死循环,导致CPU利用率接近100%
HashMap是对Map接口的实现


HashTable

HashTable的底层也是由链表+数组+红黑树实现。
无论key还是value都不能为null
它是线性安全的,使用了synchronized关键字。
HashTable实现了Map接口和Dictionary抽象类
Hashtable初始容量为11
性能比较低

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值