是什么
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射
为什么需要它
HaspMap是O(1)的
写代码时,查找元素更简洁的写法(haspMap.get(key))
实现
存储结构
hashmap储存结构.png简单说来就是 数组(hash桶)+链表+红黑树
如何找到位置
前面说了HashMap是O(1),那HashMap是怎么找到元素在hash桶中的坐标呢?
- 获取object hashcode
- 通过hashcode计算位置
2.1hashcode与hashcode的前16位与取值
2.2用前面hashcode计算的值与(数组长度-1)与计算得到所在hash桶下标
扩容
现在我们知道了HashMap的结构和如何决定元素下标,思考下HashMap长度是否是一成不变的呢?
长度变与不变我想到两个问题
1.如果长度是不变的,导致某个node一直添加元素,HashMap的复杂度不就变成了红黑树的复杂度lgn?
2.如果长度是改变的,那什么时候改变长度呢?
带着这2个问题去探寻HashMap,先说答案,HashMap的长度是改变的,长度改变即扩容与几个参数有关
1.int threshold; //要调整大小的下一个大小值(容量*加载因子)。容量默认是16
2.final float loadFactor;//哈希表的加载因子。默认为0.75
即当HashMap拥有的元素个数大于threshold,就进行扩容。
知道了上面这些扩容知识,又引发另外一个问题,扩容后,元素位置不是要进行一次重新计算?
HashMap针对这一点做了个巧妙的处理,长度是2的n次方,这样元素的位置要么不变,要么移动2的次幂位置
使用时注意事项
1.HashMap不是线程安全的
2.HashMap在多线程下可能会导致死循环
jdk1.7.0_79跟代码
死循环是因为jdk7插入元素是前插法,在resize时会进行反转链表,多线程下就造成了死循环;网上很多用3,5,7演示死循环示例,看jdk1.7.0_79的源码发现,不管怎么样都不可能造成死循环,因为1是在resize后才把元素加进去,2是因为resize判断的2个条件,要size大于阀值,并且放的元素的index里面已经有值
jdk1.8.0_201跟代码
死循环是多线程情况下在红黑树里面造成的死循环,具体原因,由于我还没弄懂红黑树,没搞清楚
网友评论