1、主要参数
桶容量(Capacity)默认16
极限容量为2的30次方
加载因子为0.75f
阈值,当map中entry数量大于此阈值时进行扩容,数组大小*加载因子
2、数据结构
JDK1.7及以前是用数组+单链表 Entry<K,V>[] table
Entry内部类如下:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
}
JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间
允许null值与null键
3、计算规则
hash算法是计算key值得到哈希桶的下标值即索引值。
目的使元素分布均匀,提高查询效率。
JDK1.8: return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
JDK1.7: return h & (length-1);
4、碰撞
如何避免:使用好的hash算法,扩容机制
具体描述:hashMap的数据结构,hash算法实现过程,扩容机制使用场景
5、扩容
HashMap实际容量是2的n次方,当元素个数大于扩容阈值,扩容到原来的两倍,并重新计算存储位置
JDK1.8: 扩容位置 = 原位置 or 原位置+旧容量
JDK1.7: 按照原来计算方法进行 h & (length-1)
6、HashMap查询
分四步:
- 判断key,根据key算出索引。
- 根据索引获得索引位置所对应的键值对链表。
- 遍历键值对链表,根据key找到对应的Entry键值对。
- 拿到value
7、HashMap增加元素
- 接收需存储的键值对
- 根据key值计算索引值
- 根据计算的hash值找到数组下标
- 判断是否产生冲突,否存入到相应数组位置
- 冲突的话判断是否红黑树还是单链表
- 红黑树结构尾插法插入或者覆盖,链表长度>8使用红黑树结构,<8使用单链表结构
8.HashMap的长度为什么是2的倍数
在HashMap的操作流程中,首先会对key进行hash算法得到一个索引值,这个索引值就是对应哈希桶数组的索引。为了得到这个索引值必须对扰动后的数跟数组长度进行取余运算。即 hash % n (n为hashmap的长度),又因为&比%运算快。n如果为2的倍数,就可以将%转换为&,结果就是 hash & (n-1)。所以这就解释了为什么HashMap长度是2的倍数。也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方,尽量较少碰撞,也就是要尽量把数据分配均匀
9、工作原理
基于hashing原理,通过put()和get()方法存储和获取对象。使用put()方法时候,通过键值对使用方法hashCode()计算hashCode,然后找到对应的索引位置存放数据;使用get()方法时候,通过equals()方法找到正确的键值,然后返回对象,如果发生碰撞,调用循环遍历list,通过keys.equals()找到正确的点