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

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

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

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

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

具体请看下列源码解析:

  1. /**
  2. * 数据结构原理几乎与HashMap一致;
  3. * WeakHashMap 不会阻止Entry.key被回收;
  4. * WeakHashMap中的每个key都是通过weakreference引用;
  5. *
  6. * expuntgeStaleEntries():清除 key已被回收 的entry,进而entry.value也被回收
  7. * WeakHashMap中所有的public的增删改查方法都直接或间接调用了expuntgeStaleEntries()方法;
  8. *
  9. * @since 1.2
  10. */
  11. public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {
  12. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  13. private static final int MAXIMUM_CAPACITY = 1 << 30;
  14. private static final float DEFAULT_LOAD_FACTOR = 0.75f;
  15. Entry<K, V>[] table;
  16. private int size;
  17. private int threshold;
  18. private final float loadFactor;
  19. // 当key被回收时,其Entry(继承自WeakReference)对象会被添加到该队列中
  20. private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
  21. int modCount;
  22. static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
  23. transient boolean useAltHashing;
  24. transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
  25. // 各种构造器,与HashMap没有太大区别,hash算法相关代码,省略......
  26. // 清除那些key已经被回收的entry
  27. // WeakHashMap 中所有的public的增删改查方法都直接或间接调用了expuntgeStaleEntries()方法
  28. // 如果在添加元素到 WeakHashMap 后,如果不再调用任何该 WeakHashMap 的方法,
  29. // 那么 Entry 不会被回收,进而 Entry.value 不会被回收
  30. private void expungeStaleEntries() {
  31. // weakreference被回收时,会被添加到其注册的referencequeue中
  32. for (Object x; (x = queue.poll()) != null;) {
  33. synchronized (queue) {
  34. @SuppressWarnings("unchecked")
  35. Entry<K, V> e = (Entry<K, V>) x;
  36. int i = indexFor(e.hash, table.length);
  37. Entry<K, V> prev = table[i];
  38. Entry<K, V> p = prev;
  39. while (p != null) {
  40. Entry<K, V> next = p.next;
  41. if (p == e) {
  42. if (prev == e)
  43. table[i] = next;
  44. else
  45. prev.next = next;
  46. // 既然key被清除了,这里把value也清除掉(帮助GC)
  47. // 其实这里也可以不清除value,因为这里将entry从链表中移除了,等于entry被删除了,虚拟机在之后的某个时间会将entry回收掉
  48. e.value = null; // Help GC
  49. size--;
  50. break;
  51. }
  52. prev = p;
  53. p = next;
  54. }
  55. }
  56. }
  57. }
  58. private Entry<K, V>[] getTable() {
  59. expungeStaleEntries();
  60. return table;
  61. }
  62. public int size() {
  63. if (size == 0)
  64. return 0;
  65. expungeStaleEntries();
  66. return size;
  67. }
  68. public V get(Object key) {
  69. Object k = maskNull(key);
  70. int h = hash(k);
  71. Entry<K, V>[] tab = getTable();
  72. int index = indexFor(h, tab.length);
  73. Entry<K, V> e = tab[index];
  74. while (e != null) {
  75. if (e.hash == h && eq(k, e.get()))
  76. return e.value;
  77. e = e.next;
  78. }
  79. return null;
  80. }
  81. public boolean containsKey(Object key) {
  82. return getEntry(key) != null;
  83. }
  84. Entry<K, V> getEntry(Object key) {
  85. Object k = maskNull(key);
  86. int h = hash(k);
  87. Entry<K, V>[] tab = getTable();
  88. int index = indexFor(h, tab.length);
  89. Entry<K, V> e = tab[index];
  90. while (e != null && !(e.hash == h && eq(k, e.get())))
  91. e = e.next;
  92. return e;
  93. }
  94. public V put(K key, V value) {
  95. Object k = maskNull(key);
  96. int h = hash(k);
  97. Entry<K, V>[] tab = getTable();// getTable() 调用了 expungeStaleEntries()
  98. int i = indexFor(h, tab.length);
  99. for (Entry<K, V> e = tab[i]; e != null; e = e.next) {
  100. if (h == e.hash && eq(k, e.get())) {
  101. V oldValue = e.value;
  102. if (value != oldValue)
  103. e.value = value;
  104. return oldValue;
  105. }
  106. }
  107. modCount++;
  108. Entry<K, V> e = tab[i];
  109. tab[i] = new Entry<>(k, value, queue, h, e);
  110. if (++size >= threshold)
  111. resize(tab.length * 2);
  112. return null;
  113. }
  114. // 与HashMap极度相似的代码,省略......
  115. public V remove(Object key) {
  116. Object k = maskNull(key);
  117. int h = hash(k);
  118. Entry<K, V>[] tab = getTable();
  119. int i = indexFor(h, tab.length);
  120. Entry<K, V> prev = tab[i];
  121. Entry<K, V> e = prev;
  122. while (e != null) {
  123. Entry<K, V> next = e.next;
  124. if (h == e.hash && eq(k, e.get())) {
  125. modCount++;
  126. size--;
  127. if (prev == e)
  128. tab[i] = next;
  129. else
  130. prev.next = next;
  131. return e.value;
  132. }
  133. prev = e;
  134. e = next;
  135. }
  136. return null;
  137. }
  138. public void clear() {
  139. // 清空队列中的所有weakreference
  140. while (queue.poll() != null)
  141. ;
  142. modCount++;
  143. // 清空所有Entry
  144. Arrays.fill(table, null);
  145. size = 0;
  146. while (queue.poll() != null)
  147. ;
  148. }
  149. // Entry为WeakReference的子类,作为弱引用指向key
  150. private static class Entry<K, V> extends WeakReference<Object> implements Map.Entry<K, V> {
  151. V value;
  152. int hash;
  153. Entry<K, V> next;
  154. Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K, V> next) {
  155. super(key, queue);// 这里就确定了该 WeakReference 指向 key (referent 变量值为 key)
  156. this.value = value;// 对 value 的引用为强引用,所以必须手动回收(通过 expungeStaleEntries())
  157. this.hash = hash;
  158. this.next = next;
  159. }
  160. @SuppressWarnings("unchecked")
  161. public K getKey() {
  162. return (K) WeakHashMap.unmaskNull(get());
  163. }
  164. public V getValue() {
  165. return value;
  166. }
  167. public V setValue(V newValue) {
  168. V oldValue = value;
  169. value = newValue;
  170. return oldValue;
  171. }
  172. public boolean equals(Object o) {
  173. if (!(o instanceof Map.Entry))
  174. return false;
  175. Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
  176. K k1 = getKey();
  177. Object k2 = e.getKey();
  178. if (k1 == k2 || (k1 != null && k1.equals(k2))) {
  179. V v1 = getValue();
  180. Object v2 = e.getValue();
  181. if (v1 == v2 || (v1 != null && v1.equals(v2)))
  182. return true;
  183. }
  184. return false;
  185. }
  186. public int hashCode() {
  187. K k = getKey();
  188. V v = getValue();
  189. return ((k == null ? 0 : k.hashCode()) ^ (v == null ? 0 : v.hashCode()));
  190. }
  191. public String toString() {
  192. return getKey() + "=" + getValue();
  193. }
  194. }
  195. // 各种迭代器,遍历方式,省略......
  196. }

Java容器解析系列(13) WeakHashMap详解的更多相关文章

  1. Java容器解析系列(11) HashMap 详解

    本篇我们来介绍一个最常用的Map结构--HashMap 关于HashMap,关于其基本原理,网上对其进行讲解的博客非常多,且很多都写的比较好,所以.... 这里直接贴上地址: 关于hash算法: Ha ...

  2. Java容器解析系列(7) ArrayDeque 详解

    ArrayDeque,从名字上就可以看出来,其是通过数组实现的双端队列,我们先来看其源码: /** 有自动扩容机制; 不是线程安全的; 不允许添加null; 作为栈使用时比java.util.Stac ...

  3. Java容器解析系列(9) PrioriyQueue详解

    PriorityQueue:优先级队列; 在介绍该类之前,我们需要先了解一种数据结构--堆,在有些书上也直接称之为优先队列: 堆(Heap)是是具有下列性质的完全二叉树:每个结点的值都 >= 其 ...

  4. Java容器解析系列(14) IdentityHashMap详解

    IdentityHashMap,使用什么的跟HashMap相同,主要不同点在于: 数据结构:使用一个数组table来存储 key:value,table[2k] 为key, table[2k + 1] ...

  5. Java容器解析系列(17) LruCache详解

    在之前讲LinkedHashMap的时候,我们说起可以用来实现LRU(least recent used)算法,接下来我看一下其中的一个具体实现-----android sdk 中的LruCache. ...

  6. Java容器解析系列(12) LinkedHashMap 详解

    LinkedHashMap继承自HashMap,除了提供HashMap的功能外,LinkedHashMap还是维护一个双向链表(实际为带头结点的双向循环链表),持有所有的键值对的引用: 这个双向链表定 ...

  7. Java容器解析系列(0) 开篇

    最近刚好学习完成数据结构与算法相关内容: Data-Structures-and-Algorithm-Analysis 想结合Java中的容器类加深一下理解,因为之前对Java的容器类理解不是很深刻, ...

  8. Java容器解析系列(10) Map AbstractMap 详解

    前面介绍了List和Queue相关源码,这篇开始,我们先来学习一种java集合中的除Collection外的另一个分支------Map,这一分支的类图结构如下: 这里为什么不先介绍Set相关:因为很 ...

  9. Java容器解析系列(6) Queue Deque AbstractQueue 详解

    首先我们来看一下Queue接口: /** * @since 1.5 */ public interface Queue<E> extends Collection<E> { / ...

随机推荐

  1. HDU 2068 RPG错排 [错排公式]

    1.题意:1到N的序列的排列中,元素位置与元素值相对应的情况(值为i的元素在某个排列中正好排在第i个位置)大于等于序列规模一半的情况,有多少个? 2.输入输出:每组数据一个数,N,规定输入以0结尾: ...

  2. Visio数据视觉化处理

    形状数据的查看的两种方式 定义形状数据:右键单击数据窗口 打勾的代表可以显示 其他没有打勾的就必须要在开发模式才会显示出来 开发模式就是打开开发工具面板 注意其中类型的设置 类型与格式是一一对应的 不 ...

  3. shelve模块、re模块

    在模糊匹配时使用 1

  4. 什么是激励函数 (Activation Function)

    relu sigmoid tanh 激励函数. 可以创立自己的激励函数解决自己的问题,只要保证这些激励函数是可以微分的. 只有两三层的神经网络,随便使用哪个激励函数都可以. 多层的不能随便选择,涉及梯 ...

  5. java xml的读取与写入(dom)

    首先,先获取到文档对象 private static Document getDocument(String path) { //1.创建DocumentBuilderFactory对象 Docume ...

  6. Visual Studio 2017 安装心得

    既然VS2017已经发布了,就想安装一下试试,先卸载VS2015, 网上有个完全卸载的东东,https://github.com/Microsoft/VisualStudioUninstaller/r ...

  7. iptables详细参数讲解

    table 表 --> chain 链 --->rule 规则Commands:Either long or short options are allowed. --append -A ...

  8. 【题解】P4091 [HEOI2016/TJOI2016]求和

    [题解]P4091 [HEOI2016/TJOI2016]求和 [P4091 HEOI2016/TJOI2016]求和 可以知道\(i,j\)从\(0\)开始是可以的,因为这个时候等于\(0\).这种 ...

  9. iOS获取网络数据/路径中的文件名

    NSString * urlString = @"http://www.baidu.com/img/baidu_logo_fqj_10.gif"; //方法一:最直接 NSStri ...

  10. list查询

    public List<MISSINGISTEMS> getMissList(MISSINGISTEMS missingistems) throws Exception { List< ...