线程不安全,线程异步,键值对存值,可以用null做键,键不可以重复
原理:hashing原理
使用put(key,value)时,键调用hashcode()方法获取hashcode,找到
bucket位置来存储entry对象。bucket中储存键对象和值对象,作为Map.Entry。
当两个对象的hashcode相同会发生什么?
因为二者的hashcode值相同,所以在bucket的位置是相同的,会发生碰
撞,因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中
如果两个键的hashcode相同,你如何获取值对象?
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位
置,因为HashMap在链表中存储的是键值对 找到bucket位置之后,会调
用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。
如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?
默认的负载因子大小为0.75,也就是说,当一个map填满了75%的
bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来
HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来
的对象放入新的bucket数组中。
你了解重新调整HashMap大小存在什么问题吗?
当重新调整HashMap大小的时候,存在条件竞争,因为如果两个
线程都发现HashMap需要重新调整大小了,它们会同时试着调整大
小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为
移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾
部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件
竞争发生了,那么就死循环了。
总结
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对
象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方
法来计算hashcode,然后找到bucket位置来储存值对象。当获取对象
时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。
HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链
表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。
当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同
一个bucket位置的链表中。键对象的equals()方法用来找到键值对。
链表
一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序
是通过链表中的指针链接次序实现的。一系列节点组成,在运行时动态
生成,每个几点有两部分:一个是存储数据元素的数据域,另一个是存
储下一个结点地址的指针域。
网友评论