WeakHashMap實現了Map接口,是HashMap的一種實現,他使用弱引用作為內部數據的存儲方案,WeakHashMap可以作為簡單緩存表的解決方案,當系統內存不夠的時候,垃圾收集器會自動的清除沒有在其他任何地方被引用的鍵值對。
如果需要用一張很大的HashMap作為緩存表,那么可以考慮使用WeakHashMap,當鍵值不存在的時候添加到表中,存在即取出其值。
WeakHashMap weakMap = new WeakHashMap<Integer, byte[]>(); for(int i = 0; i < 10000; i++){ Integer ii = new Integer(i); weakMap.put(ii, new byte[i]); }
HashMap map = new HashMap<Integer, byte[]>(); for (int i = 0; i < 10000; i++) { Integer ii = new Integer(i); map.put(ii, new byte[i]); }
這2段代碼分別用-Xmx5M的參數運行,運行的結果是第一段代碼可以很好的運行,第二段代碼會出現“Java Heap Space”的錯誤,這說明用WeakHashMap存儲,在系統內存不夠用的時候會自動回收內存。
如果WeakHashMap的key在系統內持有強引用,那么WeakHashMap就退化為HashMap,所有的表項無法被垃圾收集器自動清理。

1 package com.froest.excel; 2 3 import java.util.Iterator; 4 import java.util.Map; 5 import java.util.WeakHashMap; 6 7 public class Test5 { 8 9 /** 10 * @param args 11 */ 12 public static void main(String[] args) { 13 // TODO Auto-generated method stub 14 WeakHashMap<AA, People1> weakMap1 = new WeakHashMap<AA, People1>(); 15 String b = new String("louhang1"); 16 AA a = new AA(b); 17 BB bb = new BB(a); 18 People1 p1 = new People1(bb); 19 weakMap1.put(p1.getB().getAA(), p1); 20 p1.getB().setAA(null);// 去除對象a的強引用 21 a = null;// 去除對象a的強引用,並讓垃圾收集器回收AA對象在堆中的內存 22 System.gc(); 23 Iterator i = weakMap1.entrySet().iterator(); 24 while (i.hasNext()) { 25 Map.Entry en = (Map.Entry) i.next(); 26 System.out.println("weakMap:" + en.getKey() + ":" + en.getValue()); 27 } 28 } 29 } 30 31 class AA { 32 private String a; 33 34 public AA(String a) { 35 this.a = a; 36 } 37 38 public String getA() { 39 return a; 40 } 41 42 public void setA(String a) { 43 this.a = a; 44 } 45 } 46 47 class BB { 48 private AA a; 49 50 public BB(AA a) { 51 this.a = a; 52 } 53 54 public AA getAA() { 55 return a; 56 } 57 58 public void setAA(AA a) { 59 this.a = a; 60 } 61 } 62 63 class People1 { 64 private BB b; 65 66 public People1(BB b) { 67 this.b = b; 68 } 69 70 public BB getB() { 71 return b; 72 } 73 74 public void setB(BB b) { 75 this.b = b; 76 } 77 }
運行上面代碼以后沒有輸出任何結果,說明,WeakHashMap中的鍵值對已經被回收了,如果注釋掉p1.getB().setAA(null);或者a = null;這2行中的任意一行都沒法清除WeakhashMap中的鍵值對。
在WeakHashMap的get(),put()函數中的getTable()方法會調用expungeStateEntries方法,以清理持有弱引用的key的表項。exPungeStateEntries方法源代碼:

1 private void expungeStaleEntries() { 2 Entry<K,V> e; 3 while ( (e = (Entry<K,V>) queue.poll()) != null) { 4 int h = e.hash; 5 int i = indexFor(h, table.length); 6 7 Entry<K,V> prev = table[i]; 8 Entry<K,V> p = prev; 9 while (p != null) { 10 Entry<K,V> next = p.next; 11 if (p == e) { 12 if (prev == e) 13 table[i] = next; 14 else 15 prev.next = next; 16 e.next = null; // Help GC 17 e.value = null; // " " 18 size--; 19 break; 20 } 21 prev = p; 22 p = next; 23 } 24 } 25 }
在第二個while循環中會移除已經被回收的表項。