一、类图
二、源码分析
a. WeakHashMap 的 Key 是弱引用的,也就是 Key 放在 map 结构中不阻止对其进行垃圾回收
b. WeakHashMap 的 Value 是强引用,只有对应的 Key 被回收,才会回收
c. Value 不应直接或间接引用 Key,否则会阻止对 Key 的回收,一种处理方法是插入前弱化 Value
m.put(key, new WeakReference(value))
d. iterator 在 WeakHashMap 结构变化后会立即失败 ConcurrentModificationException,除非是迭代器执行 remove
f. 初始容量是 16,容量必须是 2 的整数次幂,hashcode &(容量 - 1)正好是数组 index 下标
2^4=16 , hashcode & 15 = hashcode & 1111 ==> 只取 hashcode 末尾几位作为 map 数组下标
g. 最大容量 1 << 30 == 2^30 == 1073741824 ,最大容量必须是 2 的整数次幂,原因同上
h. 默认装载因子 load factor 0.75f
i. 内部 table 始终应该为 2 的整数次幂
j. 内部使用一个整数变量 modCount 记录 WeakHashMap 结构变更次数,用于使迭代器快速失效
k. 构造函数如果传入不是 2 的整数次幂的大小,构造函数会自动修正
l. Null 类型的 Key,其实用的是内部的一个 Object 对象
m. 内置了一个 hash 函数,目的是二次处理 Key 对象的 hashcode,使得各位分布尽量均匀
n. WeakHashMap 的 size 不是直接返回的 size 变量值,先进行一次清理
o. 当 put 后 size >= 阈值,table 扩大为原来的二倍,重新 hash
public V put(K key, V value) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable();
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);
if (++size >= threshold)
resize(tab.length * 2);
return null;
}
void resize(int newCapacity) {
Entry<K,V>[] oldTable = getTable();
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}Entry<K,V>[] newTable = newTable(newCapacity);
transfer(oldTable, newTable);
table = newTable;/*
* 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 {
expungeStaleEntries();
transfer(newTable, oldTable); // 扩容的时候还可能发生缩容!!!
table = oldTable;
}
}
p. 使用内置的 eq 方法,判断 key 是否相等,AbstractMap 也是如此,都在 equals 基础上做了增强
q. Entry 都是静态内部类,AbstractMap 是 public 的,而此处是 private 的
r. Entry 继承了 WeakReference,关键代码,将 key 弱引用化,super(key, queue);
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
WeakReference 提供了 get() 方法获取 key,弱引用还在就能成功获取
s. 关于 WeakReference,如果它所引用的对象没有其他 Strong Reference,在下次 GC 时就会对其进行回收
因此,WeakHashMap 适合用作缓存系统,也就是说对象的创建删除很容易,但是占用内存比较大,
删除的话不会对系统有较大影响(可以很快重建缺失内容),但是能有效减少内存占用,避免内存泄漏