HashMap源码学习
HashMap线程不安全,键和值可以为空,HashTable线程安全,键和值不能为空
HashMap 采用数组加链表在JDK1.8之前,1.8之后采用数组加链表加红黑树
默认容量16
HashMap为什么默认容量为16不是15?
有2个Key的hash值为8,9
容量为16
8 &(16-1)
1000 & 1111 =1000——》8号位置
9 &(16-1)
1001 & 1111 =1001——》9号位置
容量为15
8 &(15-1)
1000 & 1110 =1000——》8号位置
9 &(15-1)
1001 & 1110 =1000——》8号位置
出现hash冲突
浪费所有Key的末位为1的
2的次方比较好
Java底层是使用c语言的,c语言底层是汇编(汇编使用的是16进制),汇编来源机器语言(01010101)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;//初始化
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//找位置
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
,当链表长度大于7时将链表转换成红黑树
大于等于8的情况下已经转为红黑树?
树化后节点不足8个?
1.6个时转换成链表
- 按照链表方式检索
目的:提高操作效率
链表
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
......
红黑树
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
......
扩容
15
1001010101原来hash值
11111 现在在31
1 15+16=31
0 15