1、数据结构
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
transient Node<K,V>[] table;
transient int size;
transient int modCount;
int threshold;
final float loadFactor;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
2、核心方法
(1)初始化,初始化指定默认大小=16,加载因子=0.75,如果指定了初始化容量,根据位或运算,最终会成为2的整数幂
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
(2)put
3、问题qa
(1)为什么默认的扩展因子是0.75
(2)1.7版本的死循环、1.8版本的死循环
1.7版本 链表头部插入,扩容成为新的链表时,仍然时头部插入,
链表 a,b,c,
线程1完成扩容,c,b,a
线程2,扩容时,显示 a--->null,然后 b-->a-->null,最后 b.next时已经发生变化,又重新指向了a,此时链表是a-->b-->a,
(3)为什么线程不安全
4、备注
(1)jdk1.8之前是插入链表头部,1.8之后是插入链表尾部
(2)jdk1.8优化,当链表个数>7时,使用红黑树进行管理