关于WeakHashMap其实没有太多可说的,其与HashMap大致相同,区别就在于:

  1. 对每个key的引用方式为弱引用;

    关于java4种引用方式,参考java Reference

    网上很多说 弱引用指向 Entry,这种说法是完全错误的

  2. key被回收时,对应的value并没有回收,只有在调用WeakHashMap的方法时才会回收value;

具体请看下列源码解析:

/**
* 数据结构原理几乎与HashMap一致;
* WeakHashMap 不会阻止Entry.key被回收;
* WeakHashMap中的每个key都是通过weakreference引用;
*
* expuntgeStaleEntries():清除 key已被回收 的entry,进而entry.value也被回收
* WeakHashMap中所有的public的增删改查方法都直接或间接调用了expuntgeStaleEntries()方法;
*
* @since 1.2
*/
public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> { private static final int DEFAULT_INITIAL_CAPACITY = 16;
private static final int MAXIMUM_CAPACITY = 1 << 30;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
Entry<K, V>[] table;
private int size;
private int threshold;
private final float loadFactor; // 当key被回收时,其Entry(继承自WeakReference)对象会被添加到该队列中
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
int modCount;
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
transient boolean useAltHashing;
transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this); // 各种构造器,与HashMap没有太大区别,hash算法相关代码,省略...... // 清除那些key已经被回收的entry
// WeakHashMap 中所有的public的增删改查方法都直接或间接调用了expuntgeStaleEntries()方法
// 如果在添加元素到 WeakHashMap 后,如果不再调用任何该 WeakHashMap 的方法,
// 那么 Entry 不会被回收,进而 Entry.value 不会被回收
private void expungeStaleEntries() {
// weakreference被回收时,会被添加到其注册的referencequeue中
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;
// 既然key被清除了,这里把value也清除掉(帮助GC)
// 其实这里也可以不清除value,因为这里将entry从链表中移除了,等于entry被删除了,虚拟机在之后的某个时间会将entry回收掉
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
} private Entry<K, V>[] getTable() {
expungeStaleEntries();
return table;
} public int size() {
if (size == 0)
return 0;
expungeStaleEntries();
return size;
} public V get(Object key) {
Object k = maskNull(key);
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;
}
return null;
} public boolean containsKey(Object key) {
return getEntry(key) != null;
} Entry<K, V> getEntry(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K, V>[] tab = getTable();
int index = indexFor(h, tab.length);
Entry<K, V> e = tab[index];
while (e != null && !(e.hash == h && eq(k, e.get())))
e = e.next;
return e;
} public V put(K key, V value) {
Object k = maskNull(key);
int h = hash(k);
Entry<K, V>[] tab = getTable();// getTable() 调用了 expungeStaleEntries()
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;
} // 与HashMap极度相似的代码,省略...... public V remove(Object key) {
Object k = maskNull(key);
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--;
if (prev == e)
tab[i] = next;
else
prev.next = next;
return e.value;
}
prev = e;
e = next;
} return null;
} public void clear() {
// 清空队列中的所有weakreference
while (queue.poll() != null)
; modCount++;
// 清空所有Entry
Arrays.fill(table, null);
size = 0; while (queue.poll() != null)
;
} // Entry为WeakReference的子类,作为弱引用指向key
private static class Entry<K, V> extends WeakReference<Object> implements Map.Entry<K, V> {
V value;
int hash;
Entry<K, V> next; Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K, V> next) {
super(key, queue);// 这里就确定了该 WeakReference 指向 key (referent 变量值为 key)
this.value = value;// 对 value 的引用为强引用,所以必须手动回收(通过 expungeStaleEntries())
this.hash = hash;
this.next = next;
} @SuppressWarnings("unchecked")
public K getKey() {
return (K) WeakHashMap.unmaskNull(get());
} public V getValue() {
return value;
} public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
} public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
K k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
V v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
} public int hashCode() {
K k = getKey();
V v = getValue();
return ((k == null ? 0 : k.hashCode()) ^ (v == null ? 0 : v.hashCode()));
} public String toString() {
return getKey() + "=" + getValue();
}
} // 各种迭代器,遍历方式,省略...... }

最新文章

  1. 前端MV*框架的意义
  2. JavaScript Patterns 5.7 Object Constants
  3. weblogic10.3.6 自动启动服务后停止的解决方案
  4. memcached缓存雪崩现象及解决办法
  5. python正则的中文处理
  6. 《转》如何让你的网页加载时间降低到 1s 内
  7. C# 判断中文字符(字符串)
  8. 【回顾整理】暴走的SQL语句练习!!!
  9. Android开发之TextView高级应用
  10. JavaScript实例技巧精选(13)—计算在网页上的停留时间
  11. codeforces 192A Funky Numbers
  12. 今天修改 wifi hal 的时候碰见一个问题
  13. 针对iOS10的各种问题的解决方法
  14. C语言位运算符:与、或、异或、取反、左移和右移
  15. Microsoft Dynamics CRM 2013/2015 选项集的多选
  16. WPF 10天修炼 第五天- 内容控件
  17. org.apache.commons.httpclient工具类
  18. redis操作(String,Hash,List,Set,其他操作)
  19. java 代码获取视频时长
  20. Array和ArrayList不同

热门文章

  1. javascript拷贝
  2. 牛客多校第四场sequence C (线段树+单调栈)
  3. 2018 CCPC 吉林站 H Lovers
  4. Linux普通用户执行特定的命令配置
  5. torch or numpy
  6. 解析crash
  7. vue项目创建步骤 和 路由router知识点
  8. k8s集群---apiserver,controller-manager,scheduler部署
  9. $tarjan$简要学习笔记
  10. 小小知识点(二十四)什么是5G