基本
hashmap有数组+链表组成
基于红黑树的hashmap就是当链表达到一定长度时把链表变成红黑树
向map中put元素,如果key重复,会覆盖并把老的元素返回出来
1 | | array | 1 | 2 | ... | N | |
- hashmap初始化数组容量的时候必须的一个二的幂次方数
- 这样方便控制取值范围
1
2
3
4
5
6
7
8
92^k-1会得到一个全是1的二进制数:0001 1111
用这个数与hash code与运算即可以截断hash code,只保留低位k-1位
0000 0111
0101 1010
---------
0000 0010
高位数先右移在与这个111与运算就可得到想要的任意位
提高散列性,防止链表过长,提高get的效率
- 这样方便控制取值范围
取小于一个数的最大二次幂算法:
1 | func (int i){ |
扩容时:新建数组 -> 迁移到新数组
多线程的情况
在多线程情况下,扩容时可能会同时创建多个个数组。在JDK1.7中会出现问题
put(key, value)方法
- 确定下标
hashcode & (lenght-1)
- 因为hashmap的长度只会是2的次幂,所以减1后每一个有效位(除了最高有效位)都是1
- 解决哈希冲突
- 计算hashcode的时候,有可能会得到同样的值,这时候发生哈希冲突
- 链表法
- 插入在链表头部(1.7)
- 再散列法
get(key)方法
- 计算下标
- 找到key对应的值
- 如果是链表法解决的哈希冲突则
- 遍历寻找key
- 如果是链表法解决的哈希冲突则
ConcurrentHashMap
ConcurrentHashMap解决多线程情况下出现的问题
ConcurrentHashMap使用一个并发级别来指定多少个元素共享一个锁,ConcurrentHashMap称这个所为segment。
- 初始化
- 根据并发级别来确定segment的容量,一个segment对象就相当于一个小的hashmap