浅读HashMap

什么是HashMap?

HashMap是Java的一个集合容器. 用于存储Key-Value对

HashMap的应用场景

假定如下场景:记录张三,李四,王五三位同学的成绩.
这时候我们有必要去做一个实体类内部包含姓名和成绩两个字段吗?
没有必要的.
完全可以利用HashMap.
存入:

Map<String,double> map=new HashMap();
map.put("张三",60.0);
map.put("李四",80.5);
map.put("王五",79);

取出:

double zhangsanScore=map.get("张三");
double lisiScore=map.get("李四");
double wangwuScore=map.get("王五";

HashMap底层(层层深入)

1.HashMap的底层结构

在1.7的时候为数组加链表的结构,节点为entry
在1.8的时候改为了数组加链表加红黑树的结构,节点为node

为什么1.8加入了红黑树?

为了提高查询效率.

为什么加入红黑树就可以提高查询效率?

因为…这个跟HashMap的关系不是特别大,关于HashMap是提高查询效率,至于是为什么,大家可以自行查阅红黑树相关的资料,后期我也会写关于二叉树,红黑树这些的文章.

为什么1.7叫node而1.8叫entry?

因为引入了红黑树,红黑树的节点叫node.避免冲突.

2.HashMap的数据插入顺序

1.7是头插法
1.8是尾插法

什么是头插法?什么是尾插法?

顾名思义,头插法就是从数据的前面插入,比如
现在数组中的数据为1,2 我要插入3之后,就变成了 3,1,2
尾插法就是从数据的尾部插入,还是上边的例子,现在数组中的数据为1,2 插入3则为1,2,3

为什么要改为尾插法?

因为头插法会导致扩容过程中出现链表循环.

什么是扩容?为什么要扩容?

为什么要扩容: 数组的长度是有限的,而我们对数据的存储需求是无限的,所以我们需要在运行的时候对数组进行扩容来满足我们的业务需求.
至于什么是扩容,往下看.

3.HashMap的扩容机制.

HashMap默认的容量是16.负载因子是0.75.

为什么默认的容量是16?

便于位运算,提高效率. 关于具体的位运算相关.可以查看位运算相关的知识.

负载因子是什么?

负载因子,怎么说呢. 可以这么说 如果 数组当前数据量大于等于容量*负载因子的结果,则进行扩容.
那么负载因子是什么?自己体会一下.

HashMap是如何扩容的?

调用resize() 然后调用transfer() 其中需要rehash()
意思就是
新建一个原数组长度2倍长的数组,然后进行数据转移,将数据重新取Hash值放到新数组上.

为什么扩大到2倍?

同默认容量16.为了便于位运算,提高效率.

为什么1.7扩容过程会出现链表循环?

在多线程情况下,因为是头插法,所以
当第一个线程 指定完指针和next后,线程暂停
然后第二个线程去操作.操作完成后 数据顺序改变
比如 原来是 1 2 3 的顺序
然后第一个线程的指针指向1 next指向2
当第二个线程操作结束后,顺序变为3 2 1
此时,第一个线程刚刚恢复.所以它的next还是2 指针还是1.
这时候就发现,next在指针之前了. 到这里就可以看出链表循环了.

这里如果有机会我会单独写一个图文文章详细解释,

为什么要rehash?

因为扩容改变了数组长度,hash取值是跟数组长度有关联的.

HashMap是线程不安全的

因为HashMap是无锁的,所以线程不是安全的.

那用谁替代HashMap来保证线程安全呢?

HashTable或ConcurrentHashMap或其它…
暂且比较HashTable和ConcurrentHashMap.
HashTable是直接在方法上加锁,效率较慢.
所以选择并发情况下性能较好的ConcurrentHashMap

未完待续…

如果您有更好的指正或补充,欢迎您不吝赐教!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值