HashMap详解

常用集合

https://i-blog.csdnimg.cn/blog_migrate/076366f342493df0cd55707ebd7b03f6.png

ArrayList :变长数组,线程不安全,初始大小10,每次扩容1.5倍;

LinkedList:双链表,读和更新差于ArrayList,增和删好于ArrayList;

Vector:古老的类,线程安全的ArrayList,每次扩容2倍;

HashSet:互异、无序的集合,基于HashMap实现,写入Key中实现去重;

LinkedHashSet:互异、有序的集合,继承自HashSet;

TreeSet:支持自然排序和定制排序,基于TreeMap实现;

HashMap:无序的键值对;

LindekHashMap:内部多了一个链表,保存Key的插入顺序,迭代的时候,比HashMap快;

TreeMap:有序的键值对,可以按照自然排序和定制排序,底层是红黑树;


HashMap

哈希冲突解决方式

  1. 开放定址法(向下寻找一个未被使用的空间)
  2. 再散列函数法
  3. 链地址法(HashMap使用的方法)

HashMap基础知识:

  1. HashMap默认长度是16,默认加载因子0.75
  2. HashMap由数组+链表组成的(1.7);
  3. HashMap由数组+链表/红黑树组成的(1.8);
  4. HashMap在调用put方法时,才会初始化table(桶数组Entry —— 1.8中变成了Node);
  5. HashMap的长度一定是2的次幂,为了支持位运算key根据长度取模),使速度更快;
  6. 树化阀值:8,多于8,链表转化为红黑树
  7. 链化阀值:6,少于6,树转化为链表
  8. 允许树化的最小桶数组容量:64
  9. 0.75是对空间和时间的折中,使节点在桶中呈泊松分布;

get值

  1. 取key的hashCode值;
  2. 高16位与低16位异或,参与运算;
  3. 与桶数组长度做取模运算,得到数组下标值;

put新值

https://i-blog.csdnimg.cn/blog_migrate/a6f32f914b700ec354948f6ec1fb310b.png

扩容

扩容条件(需要同时满足):

  1. 桶数组的被占用的数量大于等于阀值0.75;
  2. put新值的key在桶数组发生冲突;

扩容过程:

  1. 新建大数组,2倍,根据新数组的长度重新计算所有元素的hash值;
  2. 将原值一一拷贝到新数组上;

1.8优化:  

节点rehash后,要么不动,要么移动到2倍的位置,所以,1.8将节点的hash值与老数组长度进行与运算,为0的不动,为1的移动到2倍的位置;


扩展点

  1. HashMap在1.7中链表采用头插法,1.8中链表采用尾插法,是为了在多线程下避免死循环
    1. 多线程扩容时,会逆序,导致循环链表的产生,再去get一个不存在的值时,就会死循环;
    2. 1.7使用头插法是因为他们觉得后插入的元素被查找的频率会更高
  2. 1.8的get方法整体优于1.7  15%以上(Hash均匀的情况下);
  3. Hash不均匀的情况下,1.8远远优于1.7;
  4. 扩容极度消耗性能,尽可能避免扩容;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值