1.底层存储结构
底层存储结构为数组+链表+红黑树,当单个链表长度≥8且总存量达到64时,链表会进化为红黑树,更利于插入和查找
2.hashcode
- 相等(相同)的对象必须具有相等的哈希码(或者散列码)。
- 如果两个对象的hashCode相同,它们并不一定相同。
即两个对象equal()后是一样的,则hashcode()一定一样,但反之不同。
3.hashmap.put
- 扰动函数(hash方法):将hashcode与hashtable表长进行“与”&运算,以此降低冲突的概率
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
3.resize()扩容
为了解决哈希冲突导致的链化,从而影响查询效率,所以需要扩容
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
//oldTap:引用扩容器前的哈希表
//oldCap:扩容前table数组的长度
int oldCap = (oldTab == null) ? 0 : oldTab.length;
//oldThr:触发本次扩容的阈值
int oldThr = threshold;
//newCap:扩容后table数组的大小
//newThr:扩容后再次触发扩容的阈值
int newCap, newThr = 0;
//条件如果成立,说明HashMap中散列表已经初始化过了,是一次正常的扩容
if (oldCap > 0) {
//数组已经达到最大阈值,则更改阈值为int最大值(几乎不可能再达到的值)
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
//左移一位等于翻一倍,即新数组为原来数组的二倍,在小于最大容量且大于初始容量的情况下,将阈值翻倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)//默认为16
newThr = oldThr << 1; // double threshold
}
//oldThr有值有以下几种情况
//1.new HashMap(initCap,loadFactor)
//2.new HashMap(initCap)
//3.new HashMap(map)
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
//oldCap和oldThr都为0,给上默认值
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
//newThr为0时,通过newCap * loadFacto计算出来值赋给它
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
//创建出一个更大更强的数组
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
//扩容前,table不为空
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
//e为当前node节点
Node<K,V> e;
//j=0,所以是将头节点赋值给e,若头节点不为空,条件成立
if ((e = oldTab[j]) != null) {
// 将 oldTab[j]置为空,方便JVM进行GC
oldTab[j] = null;
//1.若只有单个节点,则直接将老表内的值(e)移入新表,地址为[e.hash & (newCap - 1)]
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
//2.当前节点已经树化
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
//3.桶位已经形成链表
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
以上内容全为笔者手打,欢迎大家一起交流学习!!