当前位置:数据分析 > Java宝典系列13 - WeakHashMap详细介绍(源码分析)及使用示例

Java宝典系列13 - WeakHashMap详细介绍(源码分析)及使用示例

  • 发布:2023-10-07 10:34

总结

本章我们学习WeakHashMap
我们首先对WeakHashMap有一个整体的了解,然后学习它的源码,最后通过示例学习使用WeakHashMap。 ? HashMap遍历方法
第五部分WeakHashMap示例

转载请注明出处:http://www.sychzs.cn/skywang12345/admin/EditPosts.aspx?postid=3311092

第1部分WeakHashMap简介

WeakHashMap简介

WeakHashMap 继承于 AbstractMap,并实现了 Map 接口。
和HashMap一样,WeakHashMap也是一个哈希表,并且键和值都可以为null
但是WeakHashMap的键是一个“弱键”。在WeakHashMap中,当某个key不再正常使用时,它会自动从WeakHashMap中移除。更准确地说,对于给定的键,其映射的存在并不能阻止垃圾收集器丢弃该键,这使得该键可终结、终止,然后被回收。当一个键被终止时,它对应的键值对会被有效地从映射中删除。
这个“弱密钥”的原理是什么?粗略来说,是通过WeakReference和ReferenceQueue来实现的。 WeakHashMap的key是“weak key”,其类型为WeakReference; ReferenceQueue是一个队列,它会保存GC回收的“弱键”。实现步骤为:
(01) 创建一个新的WeakHashMap,并将“键值对”添加到WeakHashMap中。
           其实WeakHashMap通过数组表来保存Entries(键值对);每个Entry实际上是一个单向链表,即Entry是一个键值对的链表。
(02) 当一个“弱键”不再被其他对象引用,且被GC回收时。当GC回收“弱键”时,“弱键”也会被添加到ReferenceQueue(队列)队列中。
(03)下次需要操作WeakHashMap时,我们会先同步表和队列。所有键值对都存储在表中,GC回收的键值对存储在队列中;为了同步它们,删除表中GC回收的键值对。
这就是“弱键”从 WeakHashMap 中自动删除的方式。

与HashMap一样,WeakHashMap也是不同步的。可以使用 Collections.synchronizedMap 方法构造同步 WeakHashMap。


WeakHashMap的构造函数

WeakHashMap 有 4 个构造函数,如下:

// 默认构造函数。 
WeakHashMap()

// 指定“容量大小”的构造函数
WeakHashMap(int容量)

// 指定“容量大小”和“负载系数”的构造函数 
WeakHashMap(int容量,浮动负载因子)

// 包含“子Map”的构造函数
WeakHashMap(Mapextends K, ? extends V> 地图)

WeakHashMap API

voidclear()
对象克隆()
boolean containsKey(对象键)
boolean containsValue(对象值)
Set>entrySet()
V get(对象键)
布尔值 isEmpty()
设置 keySet()
V put(K键,V值)void putAll(地图延伸 K, ? 延伸 V>地图)
V 删除(对象键)
int 尺寸()
收藏值()

第 2 部分 WeakHashMap 数据结构

WeakHashMap的继承关系如下

java.lang.Object
   ↳ java.util.AbstractMap
         ↳ java.util.WeakHashMap

公共WeakHashMap
    延伸抽象地图
    实现地图 {}

WeakHashMap 与 Map 的关系如下:

从图中可以看出:
(01) WeakHashMap继承于AbstractMap,实现了Map接口。
(02) WeakHashMap 是一个哈希表,但它的键是“弱键”。 WeakHashMap 保护了几个重要的成员变量:tablesizethreshold 、负载系数modCount队列
  table是一种Entry[]数组类型,Entry实际上是一个单向链表。哈希表的“键值对”存储在Entry数组中。
  size是Hashtable的大小,即Hashtable保存的键值对的数量。
  threshold是Hashtable的阈值,用于判断Hashtable的容量是否需要调整。阈值=“容量*负载系数”。
  loadFactor 是负载系数。
  modCount用于实现fail-fast机制
  queue保存已“被GC清除”的“弱引用键”。

第三部分WeakHashMap源码分析(基于JDK1.6.0_45)

下面解释一下WeakHashMap

的源码
 1  java.util;
 2 导入 java.lang.ref.WeakReference;
 3 导入 java.lang.ref.ReferenceQueue; 4
 5 公共 WeakHashMap 
 6 延伸 抽象地图
 7 工具 地图 {
 8
 9 // 默认初始容量为 16,必须为 2 的幂。 
 10 私人 静态 257最终 intDEFAULT_INITIAL_CAPACITY = 16 11
 12 //最大容量(必须是2的幂且小于2的30次方,如果传入的容量太大,将以此值替换)
 13 私人 静态 257最终 int 最大容量 = 1 << 30 14
 15 // 默认负载系数 
 16 私人 静态 257最终浮动DEFAULT_LOAD_FACTOR = 0.75f 17
 18 // 存储数据的入口数组,长度为2的幂。 19 // WeakHashMap 使用拉链方式实现。每个Entry本质上都是一个单向链表
 20 私有 Entry[] 表;
 21
 22 // WeakHashMap 的大小,即 WeakHashMap 保存的键值对数量
 23 私人 int 尺寸;
 24
 25 // WeakHashMap 的阈值,用于判断 WeakHashMap 的容量是否需要调整(阈值 = 容量 * 加载因子)  
 26 私有 int 阈值;
 27
 28 // 负载系数 实际尺寸 
 29 私人 最终 浮动负载系数;
 30
 31 // 队列存储已“被GC清除”的“弱引用键”。
 32 // 弱引用和ReferenceQueue一起使用:如果弱引用引用的对象被垃圾回收,Java虚拟机会将弱引用添加到关联的对象中。在参考队列中
 33 私有 最终参考队列队列 = newReferenceQueue();
 34 35 // WeakHashMap 被更改的次数
 36 私人 易失性 int modCount;
 37
 38 // 指定“容量大小”和“负载系数”的构造函数 
 39 public WeakHashMap(int初始容量,浮动负载系数) {
 40 if(初始容量 < 0 41 抛出  IllegalArgumentException ("非法初始容量:“+
 42 初始容量);
 43 // WeakHashMap 的最大容量只能是 MAXIMUM_CAPACITY
 44 if(初始容量 > MAXIMUM_CAPACITY)
 45 初始容量 = MAXIMUM_CAPACITY;
 46
 47 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 48 抛出 new IllegalArgumentException ("非法负载系数:“+
 49  负载系数);
 50 // 找到“大于initialCapacity”的最小2的幂
 51 int 容量 = 1 52 同时(容量<初始容量)
 53容量 <<= 1 54 // 创建Entry数组来保存数据
 55 表 =  条目[容量];
 56 // 设置“负载系数”
 57 这个.loadFactor = loadFactor;
 58 // 设置“WeakHashMap 阈值”。当WeakHashMap存储的数据量达到阈值时,需要将WeakHashMap的容量增加一倍。 
 59阈值 = (int)(容量*负载系数);
 60  }
 61 62 // 指定“容量大小”的构造函数 
 63 public WeakHashMap(intinitialCapac实体){
 64 这个(初始容量,DEFAULT_LOAD_FACTOR);
 65  }
 66
 67 // 默认构造函数。 
 68 public WeakHashMap() {
 69这个.loadFactor =DEFAULT_LOAD_FACTOR;
 70阈值 = (int)(DEFAULT_INITIAL_CAPACITY);
 71 表 =  条目 [DEFAULT_INITIAL_CAPACITY];
 72  }
 73
 74 // 包含“子Map”的构造函数
 75 public WeakHashMap(Map扩展   K, ? 延伸 V> m) {
 76 这个(Math.max((int) (m .size() / DEFAULT_LOAD_FACTOR) + 1, 16), 77DEFAULT_LOAD_FACTOR);
 78 //将m中所有元素一一添加到WeakHashMap中
 79  putAll(m);
 80  }
 81
 82 // key 为空的掩码值。
 83 // 因为WeakReference中允许“空键”,所以如果直接插入“空键”并视为弱引用,则会将其删除。
 84 // 因此,“key is null”的清除统一替换为“key is NULL_KEY”,“NULL_KEY”是一个“静态最终常量”。 
 85 私人 静态 final 对象 NULL_KEY = new Object();
 86
 87 //“空键”特殊处理
88privatestatic静态对象maskNull(对象键){
 89返回(键==null NULL_KEY :键);
 90  }
 91
 92 // 恢复“空键”特殊处理 93 私人 静态  K unmaskNull(对象键) {
 94 返回 (K) (key == NULL_KEY ? null:键);
 95  }
 96
 97 // 判断“x”和“y”是否相等
 98 静态 boolean eq(对象 x, 对象y) {
 99 返回 x == y || x.equals(y);
100  }
101
102 // 返回索引值
103 // h & (length-1) 保证返回值小于length
104 静态 int 索引For(int  h, int 长度) {
105 返回 h &(长度-1);
106  }
107
108 // 清除表中无用的键值对。原理如下:
109 // (01) 当 WeakHashMap 中的某个“弱引用键”因为不再被引用而被 GC 回收时,
110 // 回收的“弱引用key”也会被添加到“ReferenceQueue(队列)”中。
111 // (02) 当我们执行 expungeStaleEntries 时,112 // 遍历“ReferenceQueue(queue)”中的所有key
113 // 然后删除“弱引用表”中“key in ReferenceQueue(queue)”对应的键值对 
114私有voidexpungeStaleEntries(){
115条目e;
116 while ((e = (Entry)queue.poll()) != null) {
117 int h = e.hash;
118 int i =indexFor(h, table.length);
119
120条目上一个=表[i];
121条目 p =上一页;
122 同时 (p != null) {
123条目下一个=www.sychzs.cn;
124 if (p == e) {
125 if(上一页 == e)
126表[i]=下一个;
127 其他
128 上一个.下一个 = 下一个;129 www.sychzs.cn = null//帮助GC
130 e.value = null//“”
131尺寸--132打破133  }
134 上一页 = p;
135 p = 接下来;
136}
137  }
138}
139
140 // 获取WeakHashMap的表(存储键值对的数组)
141 private Entry[] getTable() {
142 // 删除表中“已被GC回收的key对应的键值对”
143  expungeStaleEntries();
144返回表;
145  }
146
147 // 获取WeakHashMap的实际大小
148公共int尺寸(){
149 if(尺寸 == 0150 返回 0151 // 删除表中“已被GC回收的key对应的键值对”152  expungeStaleEntries();
153返回尺寸;
154  }
155
156 public boolean isEmpty() {
157 返回 size() == 0;
158  }
159
160 // 获取key对应的值
161 public V get(对象键) {
162 对象 k = maskNull(key);
163 // 获取key的哈希值。 
164 int h = HashMap.hash(k.hashCode());
165 Entry[] 选项卡 = getTable();
166 int索引=indexFor(h, tab.length);
167条目 e = tab[索引];
168 // 在“哈希值对应的链表”上找到“key值等于key”的元素 
169 同时 (e != null) {
170 if (e.hash == h && eq(k, e.get()))
171 返回 e.值;
172 e = e.下一个;
173  }174返回null175  }
176
177 // WeakHashMap 是否包含 key
178 public boolean containsKey(对象键) {
179 return getEntry(key) != null;
180  }
181
182 // 返回键值对“key is key” 
183 Entry getEntry(对象键) {
184 对象 k = maskNull(key);
185 int h = HashMap.hash(k.hashCode());
186 Entry[] 选项卡 = getTable();
187int索引=indexFor(h, tab.length);
188条目 e = tab[索引];
189 同时 (e != null && !(e.hash == h &&  eq(k, e.get())))
190 e = e.下一个;
191 返回 e;
192  }
193
194 // 将“键值”添加到 WeakHashMap
195 public V put(K key, V value) {196 K k = (K) maskNull(key);
197 int h = HashMap.hash(k.hashCode());
198 Entry[] 选项卡 = getTable();
199 int i =indexFor(h, tab.length);
200
201 for(条目 e = tab[i]; e != null; e = www.sychzs.cn) {
202 // 如果“this key”对应的键值对已存在,则将旧值替换为新值。然后退出! 
203 if (h == e.hash && eq(k, e.get())) {
204 V 旧值 = e.值;
205 if(值!= 旧值)
206 e.值=值;
207 返回旧值;
208  }
209  }
210
211 // 如果 WeakHashMap 中不存在“该键”对应的键值对,则将该“键值”添加到表中 
212 modCount++213条目 e = tab[i];214 tab[i] = 条目(k, 值, 队列, h, e);
215 if(++大小 >= 阈值)
216 调整大小(制表符长度 * 2);
217返回null218  }
219
220 // 调整WeakHashMap大小,newCapacity为调整后的单位
221 void 调整大小(int newCapacity){
222 Entry[] oldTable = getTable();
223 intoldCapacity =oldTable.length;
224 if(旧容量 == MAXIMUM_CAPACITY){
225阈值= Integer.MAX_VALUE;
226 返回227  }
228
229 // 创建一个新的newTable,并将“旧表”的所有元素添加到“新newTable”中。
230 // 然后,将“新newTable”分配给“旧表”。 
231 Entry[] newTable = new Entry[newCapacity];
232  传输(旧表,新表);233桌子=新桌子;
234
235 if(大小 >= 阈值 / 2){
236阈值 = (int)(新容量*负载系数);
237 } 其他 {
238 // 删除表中“已被GC回收的key对应的键值对”
239  expungeStaleEntries();
240  传输(新表,旧表);
241桌子=旧桌子;
242  }
243  }
244
245 //将WeakHashMap中的所有元素添加到newTable中
246 private void 传输(Entry[] src,Entry[] dest){
247 for (int j = 0; j < src.length; ++j) {
248条目 e = src[j];
249 src[j] = null250 同时 (e != null) {
251条目下一个 = e.下一个;252 对象键 = e.get();
253 if(键==null){
254 www.sychzs.cn = null//帮助GC
255 e.value = null//“”
256尺寸--257 } 其他 {
258 int i =indexFor(e.hash, dest.length);
259 www.sychzs.cn = dest[i];
260 dest[i] = e;
261  }
262 e = 接下来;
263  }
264  }
265  }
266
267 //将“m”的全部元素都添加到WeakHashMap中
268 public void putAll(Mapextends  K, ? 延伸 V> m) {
269 int numKeysToBeAdded = m.size();270 if(numKeysToBeAdded == 0271 返回272
273 // 计算能力是否足够?
274 // 如果“当前实际容量 < 所需容量”,则增加容量 x2。 
275 if(numKeysToBeAdded > 阈值){
276 int 目标容量 = (int)(numKeysToBeAdded / loadFactor + 1 );
277 if(目标容量> MAXIMUM_CAPACITY)
278目标容量=MAXIMUM_CAPACITY;
279 int newCapacity = table.length;
280 while(新容量 < 目标容量)
281 新容量 <<= 1282 if(新容量 > 表.length)
283  调整大小(新容量);
284  }
285
286 // 将“m”中的元素一一添加到WeakHashMap中。 287 for(Map.Entry延伸 K, ? 延伸 V> e : m.entrySet())
288  put(e.getKey(), e.getValue());
289  }
290
291 // 删除“key is key”元素
292 public V 删除(对象键){
293 对象 k = maskNull(key);
294 // 获取哈希值。 
295 int h = HashMap.hash(k.hashCode());
296 Entry[] 选项卡 = getTable();
297 int i =indexFor(h, tab.length);
298 条目 上一个 = tab[i];
299 条目 e = 上一页;
300
301 // 删除链表中带有“key”的元素
302 // 本质是“删除单向链表中的节点”
303 同时 (e != null) {
304条目下一个=e.下一个;
305 if (h == e.hash && eq(k, e.get())) {306 modCount++307尺寸--308 if(上一页 == e)
309 tab[i] = 下一个;
310 其他
311 上一个.下一个 = 下一个;
312 返回 e.值;
313  }
314 前 = e;
315 e = 接下来;
316  }
317
318返回null319  }
320
321 // 删除“键值对”
322条目removeMapping(Object o) {
323 if (!(o 实例地图.条目))
324返回null325 Entry[] 选项卡 = getTable();
326Map.Entry条目=(Map.Entry)o;
327 对象 k = maskNull(entry.getKey());
328 int h = HashMap.hash(k.hashCode());329 int i =indexFor(h, tab.length);
330 条目 上一个 = tab[i];
331 条目 e = 上一页;
332
333 // 删除链表中的“键值对e”
334 // 本质是“删除单向链表中的节点”
335 同时 (e != null) {
336条目下一个=e.下一个;
337 if (h == e.hash && e.equals(entry)) {
338 modCount++339尺寸--340 if(上一页 == e)
341 tab[i] = 下一个;
342 其他
343 上一个.下一个 = 下一个;
344 返回 e;
345  }
346 前 = e;
347 e = 接下来;
348  }
349
350返回null351  }
352353 // 清除WeakHashMap并将所有元素设置为null
354 public voidclear() {
355 while (queue.poll() != null)
356;
357
358 modCount++359 Entry[] 选项卡 = 表;
对于 (INT I = 0; I i)
361 tab[i] = null362尺寸=0363
364 while (queue.poll() != null)
365;
366  }
367
368 //是否包含“值就是值”元素
369 public boolean containsValue(对象值){
370 // 如果“value 为 null”,则调用 containsNullValue() 查找 
371 if(值==null372 返回 containsNullValue();
373
374 // 如果“value不为空”,则查找WeakHashMap中是否存在有value的节点。 375 Entry[] 选项卡 = getTable();
376 for (int i = tab.length ; i-- > 0;)
377 for(条目 e = tab[i] ; e != null ; e =  e.下一个)
378 if (value.equals(e.value))
379返回380返回381  }
382
383 // 是否包含null值
384 私有 boolean containsNullValue() {
385 Entry[] 选项卡 = getTable();
386 for (int i = tab.length ; i-- > 0;)
387 for(条目 e = tab[i] ; e != null ; e =  e.下一个)
388 if(e.value==null389返回390返回391  }
392393 // 条目是一个单向链表。
394 // 是“WeakHashMap链式存储方式”对应的链表。
395 // 实现了Map.Entry接口,即实现了getKey()、getValue()、setValue(V value)、equals(Object o)、hashCode()函数 
396私有静态类 条目扩展弱引用实现  地图。进入 {
397 私有V值;
398私人最终int  哈希;
399 //指向下一个节点
400 私人进入下一个;
401
402 // 构造函数。 
403 输入(K键、V值、
404ReferenceQueue队列,
405 int哈希,Entry下一个){
406 super(键,队列);
407 这个.value =值;
408 这个.hash =哈希;409 这个.下一个=下一个;
410  }
411
412 public K getKey() {
413 returnWeakHashMap.unmaskNull(get());
414  }
415
416 public V getValue() {
417 返回值;
418  }
419
420 public V setValue(V newValue) {
421V旧值=值;
422值=新值;
423 返回旧值;
424  }
425
426 //判断两个条目是否适合
427 //若两个条目的“key”和“value”都满足,则返回true。
428 //否则,返回false
429 public boolean 等于(对象 o){
430 if (!(o 实例地图.条目))
431返回432 Map.Entry e = (Map.Entry)o;
433 对象 k1 = getKey();
434 对象 k2 = e.getKey();
435 if (k1 == k2 || (k1 != null &&  k1.equals(k2))) {
436 对象 v1 = getValue();
437 对象 v2 = e.getValue();
438 if (v1 == v2 || (v1 != null &&  v1.equals(v2)))
439返回440  }
441返回442  }
443
444 // 实现hashCode()
445 public int hashCode() {
446 对象 k = getKey();
447 对象 v = getValue();
448 return ((k==null ? 0 : k.hashCode()) ^449 (v==null ? 0 : v.hashCode()));
450  }
451
452 public String toString() {
453 return getKey() + "=" + getValue();
454  }
455  }
456
457 // HashIterator 是 WeakHashMap 迭代器的抽象父类,实现了公共函数。
458 // 包含3个子类:“键迭代器(KeyIterator)”、“值迭代器(ValueIterator)”和“条目迭代器(EntryIterator)”。 
459私有抽象类  HashIterator 实现迭代器 {
460 // 当前索引
461 int 索引;
462 // 当前元素
463条目条目=null464 // 最后返回的元素
465条目最后返回=null;
466 // ExpectedModCount 用于实现快速失败机制。 467 int预期ModCount = modCount;
468
469 // 下一个键(强引用)
470 对象 nextKey = null;
471
472 // 当前键(强参考)
473 对象 currentKey = null474
475 // 构造函数 
476  HashIterator() {
477索引 = (size() != 0 ? table.length : 0);
478  }
479
480 // 是否有下一个元素
481 public boolean hasNext() {
482 Entry[] t = 表;
483
484 // 条目是一个单向链表
485 // 如果Entry的下一个节点不为空,则指向next到下一个节点;
486 // 否则,指向下一个链表(也是下一个Entry)中不为空的节点。 
487 while (nextKey == null) {
488条目 e =条目;489 int i = 索引;
490 同时 (e == null && i > 0)
491 e = t[--i];
492条目= e;
493指数 = i;
494 if(e == null){
495当前Key = null496返回497  }
498 nextKey = e.get(); // 按住强参考键
499 if(nextKey == null500条目=条目.下一个;
501  }
502返回503  }
504
505 // 获取下一个元素
506 受保护条目 nextEntry() {
507 if (modCount !=预期ModCount)508 抛出 new ConcurrentModificationException();
509 if (nextKey == null && !有下一个())
510 抛出 new NoSuchElementException();
511
512 最后返回= 条目;
513条目=条目.下一个;
514 currentKey = nextKey;
515 nextKey = null516 返回最后返回;
517  }
518
519 // 当前删除元素
520 公共 void 删除(){
521 if(最后返回 == null522 抛出 new IllegalStateException();
523 if (modCount !=预期ModCount)
524 抛出 new ConcurrentModificationException();
525526WeakHashMap.这个.remove(currentKey);
527预期ModCount = modCount;
528最后返回=529当前Key = null530  }
531
532  }
533
534 //迭代器的值
535 私有  ValueIterator 扩展 HashIterator {
536 公共 V next() {
537 返回 nextEntry().value;
538}
539  }
540
541 //关键的迭代器
542 私有  KeyIterator 扩展 HashIterator {
543 公共 K next() {
550 返回 nextEntry().getKey();
545  }
546  }
547
548 //入口迭代器549 私有  EntryIterator 扩展 HashIterator> {
550 publicMap.Entry next() {
551 返回 nextEntry();
552  }
553  }
554
555 //WeakHashMap的Entry对应的集合
556 private 瞬态 Set> EntrySet = 557
558 //返回一个“密钥集合”,实际上返回一个“KeySet对象”
559 public 设置 keySet() {
560设置 ks =按键集;
561 返回 (ks != null ? ks : (keySet =  newKeySet()));
562  }
563
564 // 按键对应设置
565 //KeySet继承自AbstractSet,表示集合中没有重复的Key。 
566 私有 密钥集扩展 摘要集 {567 public迭代器迭代器(){
568 返回 new KeyIterator();
569  }
570
571 公共int尺寸(){
572 returnWeakHashMap.this.size();
573}
574
575 public boolean 包含(对象 o){
576 返回 containsKey(o);
577}
578
579 public boolean 删除(对象o){
580 if(包含Key(o)){
581WeakHashMap.这个.remove(o);
582返回583 }
584 其他
585返回586  }
587
588 public voidclear() {589WeakHashMap.这个.clear();
590  }
591  }
592
593 //返回“值集合”,实际上返回的是一个Values对象
594 公共集合值(){
595集合 vs =值;
596 返回(vs!= null ? vs :(值= 新值()));
597  }
598
599 //“超值收藏”
600 // Values继承自AbstractCollection,与“KeySet继承自AbstractSet”不同。
601 // Values中的元素可以重复。因为不同的键可以指向同一个值。 
602 私有 值​​扩展 抽象集合 {
603 公共迭代器迭代器(){
604 返回 new ValueIterator();
605 }
606
607公共int尺寸(){608 returnWeakHashMap.this.size();
609  }
610
611 public boolean 包含(对象 o){
612 返回 containsValue(o);
613}
614
615 public voidclear() {
616WeakHashMap.这个.clear();
617  }
618}
619
620 // 返回“WeakHashMap 的条目集合”
621 // 它实际上返回一个 EntrySet 对象 
622 public Set> EntrySet() {
623Set> es =entrySet;
624返回es!=null? es : (entrySet =  new EntrySet());
625}
626
627 // EntrySet 对应的集合
628 // EntrySet继承于AbstractSet,表示这个集合中没有重复的EntrySet。 629 私有  EntrySet 扩展  AbstractSet> {
630 public 迭代器> iterator() {
631 返回 new EntryIterator();
632  }
633
634 // 是否包含“值(o)”
635 public boolean 包含(对象 o){
636 if (!(o 实例地图.条目))
637返回638 Map.Entry e = (Map.Entry)o;
639 对象 k = e.getKey();
640 候选条目= getEntry(e.getKey());
641 返回候选!= null &&候选.等于(e);
642  }
643
644 // 删除“值(o)”
645 public boolean 删除(对象o){646 returnremoveMapping(o) != null;
647  }
648
649 // 返回WeakHashMap的大小
650 公共int尺寸(){
651 return WeakHashMap.this.size();
652  }
653
654 // 清除WeakHashMap
655 公共 voidclear() {
656 WeakHashMap.这个.clear();
657  }
658
659 //复印功能。将WeakHashMap中的所有元素复制到List
660 private List> deepCopy() {
661列表>列表=ArrayList> (尺寸());
662 for(地图条目 e : 这个663 list.add(new AbstractMap.SimpleEntry(e));
664 返回列表;665  }
666
667 // 返回Entry 对应的Object[]数组
668 public Object[] toArray() {
669 返回 deepCopy().toArray();
670  }
671
672 // 返回Entry对应的T[]数组(T[]是我们创建新数组时定义的数组类型)
673 public  T[] toArray(T[] a) {
674 返回 deepCopy().toArray(a);
675  }
676  }
677 }
查看代码

说明WeakHashMap 和 HashMap 都是通过“拉链法”实现的哈希表。它们的大部分源代码都是相同的,这里只是对它们不同部分的解释。

WeakReference 是一个用“弱键”实现的哈希表。这个“弱键”的目的就是实现“键值对”的动态回收。当“弱键”不再使用时,GC会回收它,WeakReference也会删除“弱键”对应的键值对。
“弱键”就是“弱引用(WeakReference)”。在Java中,WeakReference和ReferenceQueue是联合使用的。 WeakHashMap 中也是如此:如果弱引用所引用的对象被垃圾回收,Java 虚拟机就会将该弱引用添加到与其关联的引用队列中。然后,WeakHashMap会根据“引用队列”删除“WeakHashMap中已被GC回收的‘弱键’对应的键值对”。
另外,理解上述思想的关键是通过expungeStaleEntries()函数来理解。

第四部分WeakHashMap遍历方法

4.1 遍历WeakHashMap的键值对

第一步:根据entrySet()获取WeakHashMap的“键值对”Set集合。
第二步:通过Iterator遍历“第一步”得到的集合。

// 假设map是一个WeakHashMap对象
//map中的key为String类型,value为Integer类型
整数 integ = null;
迭代器 iter = map.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry条目= (Map.Entry)www.sychzs.cn();
    //获取钥匙
    key = (String)entry.getKey();
        //获取价值integ = (整数)entry.getValue();
}

4.2 遍历WeakHashMap的key

第一步:根据keySet()获取WeakHashMap的“key”的Set集合。
第二步:通过Iterator遍历“第一步”得到的集合。

// 假设map是一个WeakHashMap对象
//map中的key为String类型,value为Integer类型
字符串键 = null;
整数 = null;
迭代器 iter = map.keySet().iterator();
while (iter.hasNext()) {
        //获取钥匙
    key = (String)www.sychzs.cn();
        //根据key获取值
    integ = (整数)map.get(key);
}

4.3 遍历WeakHashMap的值

第一步:根据value()获取WeakHashMap“值”的集合。
第二步:通过Iterator遍历“第一步”得到的集合。

// 假设map是一个WeakHashMap对象
//map中的key为String类型,value为Integer类型
整数值 = null;
集合c =map.values();
迭代器 iter= c.iterator();while (iter.hasNext()) {
    value = (整数)www.sychzs.cn();
}

WeakHashMap遍历测试程序如下

 1 导入 www.sychzs.cn;
 2 导入 java.util.Random;
 3 导入 java.util.Iterator;
 4 导入 java.util.WeakHashMap;
 5 导入 java.util.HashSet;
 6 导入 java.util.Map.Entry;
 7 导入 java.util.Collection;
 8
 9 /*
 10  * @desc 遍历 WeakHashMap 的测试程序。
 11  * (01) 使用entrySet()遍历key和value,参考实现函数:
 12  * iteratorHashMapByEntryset()
 13  * (02) 使用keySet()遍历key和value,参考实现函数:
 14  * iteratorHashMapByKeyset() 15  * (03) 通过values()遍历value,参考实现函数:
 16  * iteratorHashMapJustValues()
 17  *
 18  * @author skywang
 19 */
 20 公共  WeakHashMapIteratorT东部时间{
 21
 22 公共 静态 void main(String[] args) {
 23 int val = 0 24 字符串键 = null 25 整数值 = null 26 随机 r = new 随机();
 27 WeakHashMap 映射 = new WeakHashMap();
 28
 29 对于 (int i=0; i< 12; i++) {
 30 // 随机获取 [0,100) 之间的数字 
 31 val = r.nextInt(100);
 32 33 key = String.valueOf(val);
 34值 = r.nextInt(5);
 35 // 添加到 WeakHashMap
 36 map.put(key, value);
 37 System.out.println(" key:"+key+" value:"+value);
 38  }
 39 // 通过entrySet()遍历WeakHashMap的key-value
 40  iteratorHashMapByEntryset(map);
 41
 42 //通过keySet()遍历WeakHashMap的key-value
 43  iteratorHashMapByKeyset(map) ;
 44
 45 // 遍历WeakHashMap的值即可
 46  iteratorHashMapJustValues(map);
 47  }
 48
 49 /*
 50  * 通过条目集遍历 WeakHashMap 51  * 效率高!
 52 */
 53 私人 静态 void iteratorHashMapByEntryset(WeakHashMap map) {
 54 if(地图 == null 55 返回 ;
 56
 57 System.out.println("\niterator WeakHashMap 按条目集");
 58 字符串键 = null 59 整数 integ = null 60 迭代器 iter = map.entrySet().iterator();
 61 while(iter.hasNext()) {
 62 Map.Entry 条目 = (Map.Entry)www.sychzs.cn();
 63
 64 key = (String)entry.getKey();
 65 整数= (Integer)entry.getValue();
 66 System.out.println(key+" -- "+integ.intValue()); 67  }
 68  }
 69
 70 /*
 71  * 通过keyset遍历WeakHashMap
 72  * 效率低下!
 73 */
 74 私人 静态 void iteratorHashMapByKeyset(WeakHashMap map) {
 75 if(地图==null 76 返回 ;
 77
 78 System.out.println("\niterator WeakHashMap 按键集");
 79 字符串键 = null 80 整数 integ = null 81 迭代器 iter = map.keySet().iterator();
 82 while (iter.hasNext()) {
 83 key = (String)www.sychzs.cn();
 84 integ = (整数)map.get(key); 85 System.out.println(key+" -- "+integ.intValue());
 86  }
 87  }
 88
 89
 90 /*
 91  * 遍历WeakHashMap的值
 92 */
 93 私人 静态 void iteratorHashMapJustValues(WeakHashMap map) {
 94 if(地图==null 95 返回 ;
 96
 97 集合 c = map.values();
 98 迭代器 iter= c.iterator();
 99 while (iter.hasNext()) {
100  System.out.println(www.sychzs.cn());
101  }
102  }
103 }
查看代码

 

第 5 部分 WeakHashMap 示例

下面通过实例来学习如何使用WeakHashMap

 1 导入 java.util.Iterator;
 2 导入 www.sychzs.cn;
 3 导入 java.util.WeakHashMap;
 4 导入 www.sychzs.cn;
 5 导入 java.lang.ref.WeakReference;
 6
 7 /**
 8  * @desc WeakHashMap 测试程序
 9  *
10  * @author skywang
11  * @邮箱 support@www.sychzs.cn
12 */
13 public  WeakHashMapTest {
14
15 公共 静态 void  main(String[] args) 抛出 异常 {
16  testWeakHashMapAPIs();
17  }
18
19私有静态void  testWeakHashMapAPIs() {20 // 初始化3个“弱键”
21字符串w1 = new字符串(“一”);
22字符串w2 = new字符串(“两个”);
23 String w3 = new String("三");
24 //新WeakHashMap
25 映射 wmap = new WeakHashMap();
26
27 // 添加键值对
28 wmap.put(w1, "w1");
29 wmap.put(w2, "w2");
30 wmap.put(w3, "w3");
31
32 // 打印出wmap
33 System.out.printf("\nwmap:%s\n",wmap );
34
35 // containsKey(Object key):是否包含密钥key
36 System.out.printf("包含密钥二:%s\n",wmap.containsKey("二"));
37 System.out.printf("包含密钥五: %s\n",wmap.containsKey("五"));
38
39 // containsValue(Object value):是否包含value值40 System.out.printf("包含值 0 : %s\n",wmap.containsValue(new Integer(0)));
41
42 //remove(Object key):删除键key对应的键值对
43 wmap.remove("三");
44
45 System.out.printf("wmap: %s\n",wmap );
46
47
48
49 // ---- 测试WeakHashMap的自动回收功能----
50
51 // 将 w1 设置为空。
52 // 这意味着“弱键”w1不再被其他对象引用。调用gc时,WeakHashMap中“w1”对应的键值对将会被回收
53 w1 = 54 // 内存回收。这里WeakHashMap中“w1”对应的键值对会被回收
55  System.gc();
56
57 //遍历WeakHashMap
58 迭代器 iter = wmap.entrySet().iterator();
59 while (iter.hasNext()) {
60 Map.Entry en = (Map.Entry)www.sychzs.cn();61 System.out.printf("下一个: %s - %s\n",en.getKey(),en.getValue());
62}
63 // 打印WeakHashMap的实际大小
64 System.out.printf(" gc后WeakHashMap大小:%s\n", wmap.size());
65  }
66 }
查看代码

运行结果: 

wmap:{三=w3,一=w1,二=w2}
包含关键二:true
包含关键五个:false
包含值 0 : false
wmap: {一个=w1, 两个=w2}
下一个 : 两个 - w2
 gc后WeakHashMap大小:1

 

相关文章