HashMap
底层实现
jdk1.8之前:数组+链表
jdk1.8之后:数组+链表+红黑树
static final int TREEIFY_THRESHOLD = 8; //树化阈值
static final int UNTREEIFY_THRESHOLD = 6; //取消阈值
static final int MIN_TREEIFY_CAPACITY = 64; //最小树容量
当HashMap的链表长度大于8,并且数组大于64 那么 HashMap底层会由 数组+链表 —》数组+红黑树
TREEIFY_THRESHOLD参数和MIN_TREEIFY_CAPACITY参数就是用来判断 是否达到条件的
而UNTREEIFY_THRESHOLD参数的作用是 当红黑树下 挂的节点小于或者等于6的时候 就会从红黑树—》链表
HashMap是怎么存储数据
这里我们要了解 HashMap是怎么存储数据的 链表又是怎么回事
transient HashMap.Node<K, V>[] table;
transient Set<Entry<K, V>> entrySet;
static class Node<K, V> implements Entry<K, V> {
final int hash;
final K key;
V value;
HashMap.Node<K, V> next;
Node(int var1, K var2, V var3, HashMap.Node<K, V> var4) {
this.hash = var1;
this.key = var2;
this.value = var3;
this.next = var4;
}
在调用PUT方法时,会对传入的key进行哈希运算得到一个hashcode,然后再通过**(逻辑与)操作得到一个数组下标**,最后将key+value存在这个数组下标处。
确定了key+value该存的位置之后,对于不同的参数可能会得到相同的HashCode,也就是会发生哈希冲突,反应到HashMap中就是,当PUT两个不同的key时可能会得到相同的HashCode从而得到相同的数组下标,其实在HashMap中就算key所对应的HashCode不一样,那么也有可能在经过逻辑与操作之后得到相同的数组下标,那么这时HashMap就是通过链表来处理
扩容
static final int DEFAULT_INITIAL_CAPACITY = 16;
HashMap的默认长度是16
static final float DEFAULT_LOAD_FACTOR = 0.75F; //默认负载系数
触发扩容的条件是:达到当前长度的0.75 比如当前长度为16 那么当存入的数据达到:16*0.75 = 12 时 就会进行扩容 每次扩容是按2倍进行的
在jdk1.8之前 是采用的头插法
在jdk1.8之后 是尾插法