每天进步一点点简友广场想法

HashMap 简析

2021-04-26  本文已影响0人  zcwfeng

HashMap 的主要用途

HashMap基于Map接口实现<key,value>存储结构,允许null,同时无序,线程不安全

底层实现,数组+链表+红黑树(1.8)

查找数据根据Key的hashcode 计算具体存储位置

HashMap最多只允许一条key=null的记录

HashMap增删改查效率不错,是ArrayList和LinkedList的折中实现

阈值threshold 容量

`细节`

底层数组:Node<K,V> table,充当哈希表的作用,存储hash的位置元素Node<K,V> 数组长度总是2的N次幂

负载因子:loadFactor,默认是0.75


1.根据插入Key的hash值,通过(n-1)& hash 「当前元素的hash值&hash表长度-1」---hash值%hash表长度,计算存储位置table[i],如果没有元素,直接放在table[i],如果存在。判断当前hash值和key是否一致,如果一致,则是修改value,覆盖value

2.如果存在table[i],但是hash值和当前操作值不一致,证明出现了hash冲突
判断头结点是否是treeNode,是的话按照红黑树方式增加节点。
如果不是就是单链表,节点插入到链表最后的位置。
判断当前链表长度是不是大于等于8,如果是把链表转换成红黑树。

3.插入成功判断当前,存储键值对的数量,大于threhold阈值扩容,

4.扩容
假设底层hash表大小16,负载0.75,存储个数 16 * 0.75 = 12 ,等于12的时候出发扩容。

负载因子越大,HashMap的装载程度越高,发生hash碰撞的几率就越大,链表拉长,效率变慢

负载因子小,链表稀疏,控件浪费,查询效率高。

使用时候,我们会预估key-value的容量size,通过size/loadFactor 计算需要初始化的容量 initialCapacity,可以避免存放到达阈值threshold频繁调用resize方法扩容

使用HashMap使用什么对象作为Key比较好,为什么

不可变对象,因为可变对象的hash值可能被改变,造成再次进行hash &(length-1) 取模运算位置改变导致数据丢失。

所以尽量选择Integer,String等不可变类型。

HashMap不安全,多线成操作会怎样

当我们对HashMap遍历,不能对HashMap添加,删除等更改操作,否则抛出ConcurrentModificationException。如果线程安全考虑使用
ConcurrentHashMap,多线程HashMap扩容resize可能导致死循环。

HashMap和HashTable的区别

1.整体结构
HashMap允许key为null,对value没处理
HashTabl的key和value都不允许为null,直接返回NPE

2.容量设定和扩容机制不一样
HashMap默认16,扩容一定是2的n次方
HashTable默认是11,扩容是原来的2被再加上1 扩容---「(oldCapacity << 1)+1」

3.hash分布方式

HashMap是key经过计算hash值,利用hash & (length-1) 取膜运算,HashTable容量不一定是2的n次方,不适用

上一篇下一篇

猜你喜欢

热点阅读