JAVA-HashMap
HashMap是一种特殊的数据结构。 既然是数据结构,就一定有应用的场景。 否则,哪个JDK的有条不紊的大师在做这个?
问题:
Q1我能做什么?
Q2有什么特别的吗?
Q3有什么好处?
A1:如果需要存储key-value pair密钥和值对,则可以使用此结构
A2:的名字中有hash,说明它与hash有关; 也可以存储“空”键-值对。
A3:表明既然是map,就有快速联系value的好处。
HashMap可以很好地解决K-V存储和查询问题。
在JDK1.7中,其本身的结构通过数组链表实现,数组中的每个元素都是链表。 通过计算key的hashcode,将hashcode存储在同一数组元素中。
在JDK1.8中,基底结构发生变化,当一个Entry链中有8个以上的元素时,会变化为红黑树
结构已有初步认识,如何使用,使用时关注哪些问题?
容量问题: HashCode计算返回的int范围达到-21亿而不是负,因此数组范围支持得不是很大。 但是,由于超大容量会带来各种问题,HashMap的默认容量为16。
使用中是否超过容量?
当然,可能会超过默认值16。 如果希望在hashmap中添加一定数量以上的KV,将触发自动容量扩展,每次为16-32-64……的两倍。 如果hashmap频繁触发容量增长,对性能的影响会很大,因此尽量设置容量后避免容量增长。
HashMap什么时候扩展? 扩张的原则是什么? 扩展规则。
HashMap具有参数负载因子loadfactor,JDK的默认值为0.75。 HashMap的kv达到容量*负载因子(例如16*0.75=12 )时,达到12个kv时会自动从16扩展到32,需要重新确定索引位置。 使用者当然可以自行定义负载因子,但不建议自行定义。 因子越大,空间利用率越大,搜索速度越慢,因子太小,空间有很多浪费。
源代码
类定义
类定义常数
键值对
扩展
put
获取
把链表变成红黑树
put
首先检查表是否为null,如果为空,则resize初始化表。
如果与计算(n - 1 )哈希值对应的桶为空,则直接插入新节点。 如果已经存在,则判断hash、k、v。 如果散列、密钥相同,则如果条件不同,覆盖上一个v的散列、密钥不匹配,则会插入新节点。 此外,根据节点类型,会插入树节点或链表节点。 如果k,v的数量大于阈值,将触发扩展resize
获取
基于key计算hash,去调查HashMap中是否存在这个节点。 根据hash和key,确认(n - 1 ) hash和key是否相等,有则取出还给,没有则没有查。
几个问题
通过以上内容,我基本了解了HashMap。 因为也有复杂的问题,所以大家可能会怀疑,但我不介意。 因为不影响使用。
HashMap的长度是2的幂吗?
为什么用(n - 1 ) hash决定桶的位置?
简而言之,是为了更有效地减少冲突的概率,提高效率。 如果想详细了解,请查看hashmap的hash源代码。
HashMap为什么线程不安全
线程安全问题必然发生在多线程的情况下。 如果有两个线程threadA、threadB,
threadA将kv插入到hashmap中。 在put操作期间,时间片正好结束,threadB开始执行。 将kv插入hashmap,然后正常插入。 如果两个线程使用同一时段,则threadA将复盖threadB中的记录。
HashMap的工作原理可以在JDK1.8中找到,但不建议使用旧版本的。