HashMap底层其实是一个k-v结构的Entry数组,同时为了解决hash冲突问题,也存在链表结构。另外在1.8版本之后,为了优化链表结构,又引入红黑树,使得数据存储更加合理。
jdk1.8之前,hashmap的默认数组长度为16,扩容机制如下
(1)、就是hashmap在存值的时候(默认大小为16,负载因子0.75,阈值12),可能达到最后存满16个值的时候,再存入第17个值才会发生扩容现象,因为前16个值,每个值在底层数组中分别占据一个位置,并没有发生hash碰撞。
(2)、当然也有可能存储更多值(超多16个值,最多可以存26个值)都还没有扩容。原理:前11个值全部hash碰撞,存到数组的同一个位置(这时元素个数小于阈值12,不会扩容),后面所有存入的15个值全部分散到数组剩下的15个位置(这时元素个数大于等于阈值,但是每次存入的元素并没有发生hash碰撞,所以不会扩容),前面11+15=26,所以在存入第27个值的时候才同时满足上面两个条件,这时候才会发生扩容现象。
jdk1.8及其以后,hashmap的默认数组长度为64,扩容机制如下
(1)、因为扩容比较消耗资源,所以应该尽量避免。但是在链表结构中,如果链表长度过长,会极大影响数据的查改效率,因此引入性能更加均衡的红黑树。
(2)、扩大数组长度也是为了减少扩容机制的触发,其负载因子与jdk1.8之前一样为0.75。但是不同于jdk1. 7,放入key之前先扩容,放入后不重新判断是否扩容。达到阀值且hash冲突时才扩容。不发生hash冲突,可超过阀值。因此jdk1.7最多存个数:threshold+table.length-1,如介绍1。jdk1.8中,放入key之后再判断是否达到阈值,超过阈值就扩容,与是否hash冲突无关,因此最多存放key个数与阀值相同。
jdk1.8中hash“冲突”时的解决方案
(1)、如果冲突数量小于8,则是以链表方式解决冲突。
(2)、而当冲突大于等于8时,就会将冲突的Entry转换为红黑树进行存储。
(3)、而又当数量小于6时,则又转化为链表存储。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。