public V put(K key, V value){ // 如果key为空,用空对象代替 Object k = maskNull(key); // 计算key的hash值 int h = hash(k); // 获取桶 Entry<K,V>[] tab = getTable(); // 计算元素在哪个桶中,h & (length-1) int i = indexFor(h, tab.length);
// 遍历桶对应的链表 for (Entry<K,V> e = tab[i]; e != null; e = e.next) { if (h == e.hash && eq(k, e.get())) { // 如果找到了元素就使用新值替换旧值,并返回旧值 V oldValue = e.value; if (value != oldValue) e.value = value; return oldValue; } }
modCount++; // 如果没找到就把新值插入到链表的头部 Entry<K,V> e = tab[i]; tab[i] = new Entry<>(k, value, queue, h, e); // 如果插入元素后数量达到了扩容门槛就把桶的数量扩容为2倍大小 if (++size >= threshold) resize(tab.length * 2); returnnull; }
/* * If ignoring null elements and processing ref queue caused massive * shrinkage, then restore old table. This should be rare, but avoids * unbounded expansion of garbage-filled tables. */ // 如果元素个数大于扩容门槛的一半,则使用新桶和新容量,并计算新的扩容门槛 if (size >= threshold / 2) { threshold = (int)(newCapacity * loadFactor); } else { // 否则把元素再转移回旧桶,还是使用旧桶 // 因为在transfer的时候会清除失效的Entry,所以元素个数可能没有那么大了,就不需要扩容了 expungeStaleEntries(); transfer(newTable, oldTable); table = oldTable; } }
privatevoidtransfer(Entry<K,V>[] src, Entry<K,V>[] dest){ // 遍历旧桶 for (int j = 0; j < src.length; ++j) { Entry<K,V> e = src[j]; src[j] = null; while (e != null) { Entry<K,V> next = e.next; Object key = e.get(); // 如果key等于了null就清除,说明key被gc清理掉了,则把整个Entry清除 if (key == null) { e.next = null; // Help GC e.value = null; // " " size--; } else { // 否则就计算在新桶中的位置并把这个元素放在新桶对应链表的头部 int i = indexFor(e.hash, dest.length); e.next = dest[i]; dest[i] = e; } e = next; } } }
判断旧容量是否达到最大容量;
新建新桶并把元素全部转移到新桶中;
如果转移后元素个数不到扩容门槛的一半,则把元素再转移回旧桶,继续使用旧桶,说明不需要扩容;
否则使用新桶,并计算新的扩容门槛;
转移元素的过程中会把key为null的元素清除掉,所以size会变小;
get(Object key)方法
获取元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public V get(Object key){ Object k = maskNull(key); // 计算hash int h = hash(k); Entry<K,V>[] tab = getTable(); int index = indexFor(h, tab.length); Entry<K,V> e = tab[index]; // 遍历链表,找到了就返回 while (e != null) { if (e.hash == h && eq(k, e.get())) return e.value; e = e.next; } returnnull; }
public V remove(Object key){ Object k = maskNull(key); // 计算hash int h = hash(k); Entry<K,V>[] tab = getTable(); int i = indexFor(h, tab.length); // 元素所在的桶的第一个元素 Entry<K,V> prev = tab[i]; Entry<K,V> e = prev;
// 遍历链表 while (e != null) { Entry<K,V> next = e.next; if (h == e.hash && eq(k, e.get())) { // 如果找到了就删除元素 modCount++; size--;
privatevoidexpungeStaleEntries(){ // 遍历引用队列 for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); // 找到所在的桶 Entry<K,V> prev = table[i]; Entry<K,V> p = prev; // 遍历链表 while (p != null) { Entry<K,V> next = p.next; // 找到该元素 if (p == e) { // 删除该元素 if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // Help GC size--; break; } prev = p; p = next; } } } }