Java集合框架之WeakHashMap詳解
WeakHashMap
WeakHashMap和HashMap相似,也是哈希表的實現(xiàn),以鍵值對的形式存儲數(shù)據(jù),key和value都可以為null。
不同的是WeakHashMap的鍵為“弱鍵”。在 WeakHashMap 中,當(dāng)某個鍵不再正常使用時,會被從WeakHashMap中被自動移除。更精確地說,對于一個給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。某個鍵被終止時,它對應(yīng)的鍵值對也就從映射中有效地移除了。
這個“弱鍵”的原理呢?大致上就是,通過WeakReference和ReferenceQueue實現(xiàn)的。
WeakHashMap的key是“弱鍵”,即是WeakReference類型的;ReferenceQueue是一個隊列,它會保存被GC回收的“弱鍵”。
實現(xiàn)步驟是:
(01) 新建WeakHashMap,將“鍵值對”添加到WeakHashMap中。
實際上,WeakHashMap是通過數(shù)組table保存Entry(鍵值對);每一個Entry實際上是一個單向鏈表,即Entry是鍵值對鏈表。
(02) 當(dāng)某“弱鍵”不再被其它對象引用,并被GC回收時。在GC回收該“弱鍵”時,這個“弱鍵”也同時會被添加到ReferenceQueue(queue)隊列中。
(03) 當(dāng)下一次我們需要操作WeakHashMap時,會先同步table和queue。table中保存了全部的鍵值對,而queue中保存被GC回收的鍵值對;同步它們,就是刪除table中被GC回收的鍵值對。
這就是“弱鍵”如何被自動從WeakHashMap中刪除的步驟了。
和HashMap一樣,WeakHashMap是不同步的。可以使用 Collections.synchronizedMap 方法來構(gòu)造同步的 WeakHashMap。
部分頂部注釋
Hash table based implementation of the Map interface, with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.
WeakHashMap是Map接口的基于弱鍵的哈希表實現(xiàn)。當(dāng)一個鍵不再正常使用,鍵對應(yīng)的鍵值對將自動從WeakHashMap中刪除。更嚴(yán)謹(jǐn)?shù)恼f法是,鍵對應(yīng)的鍵值對的存在并不阻止key被垃圾回收期回收,這就使該鍵稱為可被終止的,最終被終止,被回收。當(dāng)某個鍵被回收,它對應(yīng)的鍵值對也就被從map中有效地刪除了。所以WeakHashMap類表現(xiàn)地有些和其他的Map接口實現(xiàn)不同。
Both null values and the null key are supported. This class has performance characteristics similar to those of the HashMap class, and has the same efficiency parameters of initial capacity and load factor.
WeakHashMap特性與HashMap相似,WeakHashMap同樣支持key和value為null,也有初始化容量和負(fù)載因子等參數(shù)。
Like most collection classes, this class is not synchronized. A synchronized WeakHashMap may be constructed using the Collections.synchronizedMap method.
像大多的集合類一樣,WeakHashMap是非同步的??梢允褂肅ollections.synchronizedMap來構(gòu)造同步的WeakHashMap。
下面還有很多,不翻譯了。
從以上的內(nèi)容中我們可以總結(jié)出WeakHashMap的特點:
- WeakHashMap特性與HashMap相似,也是哈希表的實現(xiàn),以鍵值對的形式存儲數(shù)據(jù),同樣支持key和value為null,也有初始化容量和負(fù)載因子等參數(shù),也是非同步的。
- WeakHashMap的鍵為“弱鍵”。
WeakHashMap數(shù)據(jù)結(jié)構(gòu)
java.lang.Object ? java.util.AbstractMap<K, V> ? java.util.WeakHashMap<K, V> public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {}
(01) WeakHashMap繼承于AbstractMap,并且實現(xiàn)了Map接口。
(02) WeakHashMap是哈希表,但是它的鍵是"弱鍵"。
WeakHashMap中保護(hù)幾個重要的成員變量:table,size,threshold,loadFactor,modCount,queue。
- table是一個Entry[]數(shù)組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數(shù)組中的。
- size是Hashtable的大小,它是Hashtable保存的鍵值對的數(shù)量。
- threshold是Hashtable的閾值,用于判斷是否需要調(diào)整Hashtable的容量。threshold的值="容量*加載因子"。
- loadFactor就是加載因子。
- modCount是用來實現(xiàn)fail-fast機(jī)制的
- queue保存的是“已被GC清除”的“弱引用的鍵”。
源碼分析
package java.util; import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> { // 默認(rèn)的初始容量是16,必須是2的冪。 private static final int DEFAULT_INITIAL_CAPACITY = 16; // 最大容量(必須是2的冪且小于2的30次方,傳入容量過大將被這個值替換) private static final int MAXIMUM_CAPACITY = 1 << 30; // 默認(rèn)加載因子 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 存儲數(shù)據(jù)的Entry數(shù)組,長度是2的冪。 // WeakHashMap是采用拉鏈法實現(xiàn)的,每一個Entry本質(zhì)上是一個單向鏈表 Entry<K,V>[] table; // WeakHashMap的大小,它是WeakHashMap保存的鍵值對的數(shù)量 private int size; // WeakHashMap的閾值,用于判斷是否需要調(diào)整WeakHashMap的容量(threshold = 容量*加載因子) private int threshold; // 加載因子實際大小 private final float loadFactor; // queue保存的是“已被GC清除”的“弱引用的鍵”。 // 弱引用和ReferenceQueue 是聯(lián)合使用的:如果弱引用所引用的對象被垃圾回收,Java虛擬機(jī)就會把這個弱引用加入到與之關(guān)聯(lián)的引用隊列中 private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); // WeakHashMap被改變的次數(shù) int modCount; // 指定“容量大小”和“加載因子”的構(gòu)造函數(shù) public WeakHashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Initial Capacity: "+ initialCapacity); // WeakHashMap的最大容量只能是MAXIMUM_CAPACITY if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load factor: "+ loadFactor); // 找出“大于initialCapacity”的最小的2的冪 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; // 創(chuàng)建Entry數(shù)組,用來保存數(shù)據(jù) table = newTable(capacity); // 設(shè)置“加載因子” this.loadFactor = loadFactor; // 設(shè)置“WeakHashMap閾值”,當(dāng)WeakHashMap中存儲數(shù)據(jù)的數(shù)量達(dá)到threshold時,就需要將WeakHashMap的容量加倍。 threshold = (int)(capacity * loadFactor); } // 指定“容量大小”的構(gòu)造函數(shù) public WeakHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } // 默認(rèn)構(gòu)造函數(shù)。 public WeakHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } // 包含“子Map”的構(gòu)造函數(shù) public WeakHashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); // 將m中的全部元素逐個添加到WeakHashMap中 putAll(m); } // 鍵為null的mask值。 // 因為WeakReference中允許“null的key”,若直接插入“null的key”,將其當(dāng)作弱引用時,會被刪除。 // 因此,這里對于“key為null”的清空,都統(tǒng)一替換為“key為NULL_KEY”,“NULL_KEY”是“靜態(tài)的final常量”。 private static final Object NULL_KEY = new Object(); // 對“null的key”進(jìn)行特殊處理 private static Object maskNull(Object key) { return (key == null) ? NULL_KEY : key; } // 還原對“null的key”的特殊處理 static Object unmaskNull(Object key) { return (key == NULL_KEY) ? null : key; } // 判斷“x”和“y”是否相等 private static boolean eq(Object x, Object y) { return x == y || x.equals(y); } // 計算key的哈希值 final int hash(Object k) { int h = k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } // 返回哈希值對應(yīng)的index // h & (length-1)保證返回值的小于length private static int indexFor(int h, int length) { return h & (length-1); } // 清空table中無用鍵值對。原理如下: // (01) 當(dāng)WeakHashMap中某個“弱引用的key”由于沒有再被引用而被GC收回時, // 被回收的“該弱引用key”也被會被添加到"ReferenceQueue(queue)"中。 // (02) 當(dāng)我們執(zhí)行expungeStaleEntries時, // 就遍歷"ReferenceQueue(queue)"中的所有key // 然后就在“WeakReference的table”中刪除與“ReferenceQueue(queue)中key”對應(yīng)的鍵值對 private void expungeStaleEntries() { // 遍歷隊列 for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") // 由此可以看出隊列中的元素是Entry Entry<K,V> e = (Entry<K,V>) x; // 獲取entry對應(yīng)桶的index int i = indexFor(e.hash, table.length); // 根據(jù)index獲取table中對應(yīng)的桶 Entry<K,V> prev = table[i]; Entry<K,V> p = prev; // 如果桶不為null,遍歷桶中節(jié)點,找到并刪除與e相等的節(jié)點 while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator e.value = null; // 將e的value置為null size--;// table大小減1 break; } // 準(zhǔn)備遍歷下個節(jié)點 prev = p; p = next; } } } } // 獲取WeakHashMap的table(存放鍵值對的數(shù)組) private Entry<K,V>[] getTable() { // 刪除table中“已被GC回收的key對應(yīng)的鍵值對” expungeStaleEntries(); return table; } // 獲取WeakHashMap的實際大小 public int size() { if (size == 0) return 0; // 刪除table中“已被GC回收的key對應(yīng)的鍵值對” expungeStaleEntries(); return size; } public boolean isEmpty() { return size() == 0; } // 獲取key對應(yīng)的value public V get(Object key) { Object k = maskNull(key); // 獲取key的hash值。 int h = hash(k); Entry<K,V>[] tab = getTable(); int index = indexFor(h, tab.length); Entry<K,V> e = tab[index]; // 在“該hash值對應(yīng)的鏈表”上查找“鍵值等于key”的元素 while (e != null) { if (e.hash == h && eq(k, e.get())) return e.value; e = e.next; } return null; } // WeakHashMap是否包含key public boolean containsKey(Object key) { return getEntry(key) != null; } // 返回“鍵為key”的鍵值對 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; } // 將“key-value”添加到WeakHashMap中 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) { // 若“該key”對應(yīng)的鍵值對已經(jīng)存在,則用新的value取代舊的value。然后退出! if (h == e.hash && eq(k, e.get())) { V oldValue = e.value; if (value != oldValue) e.value = value; return oldValue; } } // 若“該key”對應(yīng)的鍵值對不存在于WeakHashMap中,則將“key-value”添加到table中 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; } // 重新調(diào)整WeakHashMap的大小,newCapacity是調(diào)整后的單位 void resize(int newCapacity) { Entry<K,V>[] oldTable = getTable(); // 記錄table大小 int oldCapacity = oldTable.length; // 如果table大小為MAXIMUM_CAPACITY,就將threshold調(diào)整為Integer.MAX_VALUE,終止執(zhí)行 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } // 新建一個newTable,將“舊的table”的全部元素添加到“新的newTable”中, // 然后,將“新的newTable”賦值給“舊的table”。 Entry<K,V>[] newTable = newTable(newCapacity); transfer(oldTable, newTable); table = newTable; // 如果table大小大于等于threshold / 2 if (size >= threshold / 2) { // 重新計算threshold threshold = (int)(newCapacity * loadFactor); } else { // 刪除table中“已被GC回收的key對應(yīng)的鍵值對” expungeStaleEntries(); transfer(newTable, oldTable); table = oldTable; } } // 將src的所有鍵值對復(fù)制到dest中。 private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) { for (int j = 0; j < src.length; ++j) { Entry<K,V> e = src[j]; src[j] = null; while (e != null) { Entry<K,V> next = e.next; Object key = e.get(); if (key == null) { e.next = null; // Help GC e.value = null; // " " size--; } else { int i = indexFor(e.hash, dest.length); e.next = dest[i]; dest[i] = e; } e = next; } } } // 將"m"的全部元素都添加到WeakHashMap中 public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0) return; // 計算容量是否足夠, // 若“當(dāng)前實際容量 < 需要的容量”,則將容量x2。 if (numKeysToBeAdded > threshold) { int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; while (newCapacity < targetCapacity) newCapacity <<= 1; if (newCapacity > table.length) resize(newCapacity); } // 將“m”中的元素逐個添加到WeakHashMap中。 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); } // 刪除“鍵為key”元素 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; // 刪除鏈表中“鍵為key”的元素 // 本質(zhì)是“刪除單向鏈表中的節(jié)點” 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; } // 刪除“鍵值對” boolean removeMapping(Object o) { if (!(o instanceof Map.Entry)) return false; Entry<K,V>[] tab = getTable(); Map.Entry<?,?> entry = (Map.Entry<?,?>)o; Object k = maskNull(entry.getKey()); int h = hash(k); int i = indexFor(h, tab.length); Entry<K,V> prev = tab[i]; Entry<K,V> e = prev; // 刪除鏈表中的“鍵值對e” // 本質(zhì)是“刪除單向鏈表中的節(jié)點” while (e != null) { Entry<K,V> next = e.next; if (h == e.hash && e.equals(entry)) { modCount++; size--; if (prev == e) tab[i] = next; else prev.next = next; return true; } prev = e; e = next; } return false; } // 清空WeakHashMap,將所有的元素設(shè)為null public void clear() { // clear out ref queue. We don't need to expunge entries // since table is getting cleared. while (queue.poll() != null) ; modCount++; Arrays.fill(table, null); size = 0; // Allocation of array may have caused GC, which may have caused // additional entries to go stale. Removing these entries from the // reference queue will make them eligible for reclamation. while (queue.poll() != null) ; } // 是否包含“值為value”的元素 public boolean containsValue(Object value) { // 若“value為null”,則調(diào)用containsNullValue()查找 if (value==null) return containsNullValue(); // 若“value不為null”,則查找WeakHashMap中是否有值為value的節(jié)點。 Entry<K,V>[] tab = getTable(); for (int i = tab.length; i-- > 0;) for (Entry<K,V> e = tab[i]; e != null; e = e.next) if (value.equals(e.value)) return true; return false; } // 是否包含null值 private boolean containsNullValue() { Entry<K,V>[] tab = getTable(); for (int i = tab.length; i-- > 0;) for (Entry<K,V> e = tab[i]; e != null; e = e.next) if (e.value==null) return true; return false; } // Entry是單向鏈表。 // 它是 “WeakHashMap鏈?zhǔn)酱鎯Ψā睂?yīng)的鏈表。 // 它實現(xiàn)了Map.Entry 接口,即實現(xiàn)getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函數(shù) private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { V value; final int hash; // 指向下一個節(jié)點 Entry<K,V> next; // 構(gòu)造函數(shù)。 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; } @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; } // 判斷兩個Entry是否相等 // 若兩個Entry的“key”和“value”都相等,則返回true。 // 否則,返回false 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; } // 實現(xiàn)hashCode() public int hashCode() { K k = getKey(); V v = getValue(); return Objects.hashCode(k) ^ Objects.hashCode(v); } public String toString() { return getKey() + "=" + getValue(); } } // HashIterator是WeakHashMap迭代器的抽象出來的父類,實現(xiàn)了公共了函數(shù)。 // 它包含“key迭代器(KeyIterator)”、“Value迭代器(ValueIterator)”和“Entry迭代器(EntryIterator)”3個子類。 private abstract class HashIterator<T> implements Iterator<T> { // 當(dāng)前索引 private int index; // 當(dāng)前元素 private Entry<K,V> entry; // 上一次返回元素 private Entry<K,V> lastReturned; // expectedModCount用于實現(xiàn)fast-fail機(jī)制。 private int expectedModCount = modCount; // 下一個鍵(強(qiáng)引用) private Object nextKey; // 當(dāng)前鍵(強(qiáng)引用) private Object currentKey; // 構(gòu)造函數(shù) HashIterator() { index = isEmpty() ? 0 : table.length; } // 是否存在下一個元素 public boolean hasNext() { Entry<K,V>[] t = table; // 一個Entry就是一個單向鏈表 // 若該Entry的下一個節(jié)點不為空,就將next指向下一個節(jié)點; // 否則,將next指向下一個鏈表(也是下一個Entry)的不為null的節(jié)點。 while (nextKey == null) { Entry<K,V> e = entry; int i = index; while (e == null && i > 0) e = t[--i]; entry = e; index = i; if (e == null) { currentKey = null; return false; } nextKey = e.get(); // hold on to key in strong ref if (nextKey == null) entry = entry.next; } return true; } // 獲取下一個元素 protected Entry<K,V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (nextKey == null && !hasNext()) throw new NoSuchElementException(); lastReturned = entry; entry = entry.next; currentKey = nextKey; nextKey = null; return lastReturned; } // 刪除當(dāng)前元素 public void remove() { if (lastReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); WeakHashMap.this.remove(currentKey); expectedModCount = modCount; lastReturned = null; currentKey = null; } } // value的迭代器 private class ValueIterator extends HashIterator<V> { public V next() { return nextEntry().value; } } // key的迭代器 private class KeyIterator extends HashIterator<K> { public K next() { return nextEntry().getKey(); } } // Entry的迭代器 private class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } // WeakHashMap的Entry對應(yīng)的集合 private transient Set<Map.Entry<K,V>> entrySet; // 返回“key的集合”,實際上返回一個“KeySet對象” public Set<K> keySet() { Set<K> ks = keySet; if (ks == null) { ks = new KeySet(); keySet = ks; } return ks; } // Key對應(yīng)的集合 // KeySet繼承于AbstractSet,說明該集合中沒有重復(fù)的Key。 private class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return new KeyIterator(); } public int size() { return WeakHashMap.this.size(); } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { if (containsKey(o)) { WeakHashMap.this.remove(o); return true; } else return false; } public void clear() { WeakHashMap.this.clear(); } public Spliterator<K> spliterator() { return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0); } } // 返回“value集合”,實際上返回的是一個Values對象 public Collection<V> values() { Collection<V> vs = values; if (vs == null) { vs = new Values(); values = vs; } return vs; } // “value集合” // Values繼承于AbstractCollection,不同于“KeySet繼承于AbstractSet”, // Values中的元素能夠重復(fù)。因為不同的key可以指向相同的value。 private class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return new ValueIterator(); } public int size() { return WeakHashMap.this.size(); } public boolean contains(Object o) { return containsValue(o); } public void clear() { WeakHashMap.this.clear(); } public Spliterator<V> spliterator() { return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0); } } // 返回“WeakHashMap的Entry集合” // 它實際是返回一個EntrySet對象 public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } // EntrySet對應(yīng)的集合 // EntrySet繼承于AbstractSet,說明該集合中沒有重復(fù)的EntrySet。 private class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator(); } // 是否包含“值(o)” public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; Entry<K,V> candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } // 刪除“值(o)” public boolean remove(Object o) { return removeMapping(o); } // 返回WeakHashMap的大小 public int size() { return WeakHashMap.this.size(); } // 清空WeakHashMap public void clear() { WeakHashMap.this.clear(); } // 拷貝函數(shù)。將WeakHashMap中的全部元素都拷貝到List中 private List<Map.Entry<K,V>> deepCopy() { List<Map.Entry<K,V>> list = new ArrayList<>(size()); for (Map.Entry<K,V> e : this) list.add(new AbstractMap.SimpleEntry<>(e)); return list; } // 返回Entry對應(yīng)的Object[]數(shù)組 public Object[] toArray() { return deepCopy().toArray(); } // 返回Entry對應(yīng)的T[]數(shù)組(T[]我們新建數(shù)組時,定義的數(shù)組類型) public <T> T[] toArray(T[] a) { return deepCopy().toArray(a); } public Spliterator<Map.Entry<K,V>> spliterator() { return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0); } } }
總結(jié)
WeakHashMap與HashMap比較
不同點
不同點 | HashMap | WeakHashMap |
數(shù)據(jù)結(jié)構(gòu) | 數(shù)組+鏈表+紅黑樹 | 數(shù)組+鏈表+隊列 |
鍵 | 強(qiáng)引用 | 弱引用 |
是否實現(xiàn)Cloneable和Serializable | 是 | 否 |
相同點
- 都是基于哈希表的實現(xiàn)。
- 都以鍵值對的形式存儲數(shù)據(jù)。
- 都繼承了AbstractMap,實現(xiàn)了Map接口。
- 都支持key和value為null。
- 都是非同步的。
- 都是無序的。
什么是“弱鍵”?
先了解下什么是“弱引用”
弱引用, 在進(jìn)行垃圾回收時,無論當(dāng)前內(nèi)存是否足夠,都會回收掉只被弱引用關(guān)聯(lián)著的對象,因此其生命周期只存在于一個垃圾回收周期內(nèi)。
WeakHashMap的鍵就是弱引用。當(dāng)某個鍵不再正常使用時,便自動移除其條目。
“弱鍵”會對WeakHashMap產(chǎn)生什么影響? 當(dāng)一個鍵不再正常使用,鍵對應(yīng)的鍵值對將自動從WeakHashMap中刪除。鍵對應(yīng)的鍵值對的存在并不阻止key被垃圾回收期回收,這就使該鍵稱為可被終止的,最終被終止,被回收。當(dāng)某個鍵被回收,它對應(yīng)的鍵值對也就被從map中有效地刪除了。所以WeakHashMap類表現(xiàn)地有些和其他的Map接口實現(xiàn)不同。
“弱鍵”是如何實現(xiàn)的?
WeakHashMap 中的Entry對象繼承了 WeakReference,它把key封裝成一個弱引用對象。
WeakHashMap .Entry
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { V value; final int hash; Entry<K,V> next; /** * Creates new entry. */ 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; } ... ... ...
HashMap.Node
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } ... ... ...
對比從上面WeakHashMap和HashMap節(jié)點類的實現(xiàn)可以看出,WeakHashMap把key封裝成一個弱引用對象。
想深入了解WeakHashMap的弱鍵,那么就必須先了解 ReferenceQueue 和 WeakReference。
到此這篇關(guān)于Java集合框架之WeakHashMap詳解的文章就介紹到這了,更多相關(guān)Java的WeakHashMap內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java并發(fā)編程中的Callable、Future和FutureTask詳解
這篇文章主要介紹了Java并發(fā)編程中的Callable、Future和FutureTask詳解,創(chuàng)建線程的2種方式,一種是直接繼承Thread,另外一種就是實現(xiàn)Runnable接口,這2種方式都有一個缺陷就是:在執(zhí)行完任務(wù)之后無法獲取執(zhí)行結(jié)果,需要的朋友可以參考下2023-07-07詳解SpringBoot中的tomcat優(yōu)化和修改
這篇文章主要介紹了詳解SpringBoot中的tomcat優(yōu)化和修改,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09SpringCloud Eureka服務(wù)發(fā)現(xiàn)實現(xiàn)過程
這篇文章主要介紹了SpringCloud Eureka服務(wù)發(fā)現(xiàn)實現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11Java?CopyOnWriteArrayList源碼超詳細(xì)分析
為了將讀取的性能發(fā)揮到極致,jdk中提供了CopyOnWriteArrayList類,下面這篇文章主要給大家介紹了關(guān)于java中CopyOnWriteArrayList源碼解析的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11