17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.lang.ref.WeakReference; 29 import java.lang.ref.ReferenceQueue; 30 import java.util.concurrent.ThreadLocalRandom; 31 import java.util.function.BiConsumer; 32 import java.util.function.BiFunction; 33 import java.util.function.Consumer; 34 35 36 /** 37 * Hash table based implementation of the <tt>Map</tt> interface, with 38 * <em>weak keys</em>. 39 * An entry in a <tt>WeakHashMap</tt> will automatically be removed when 40 * its key is no longer in ordinary use. More precisely, the presence of a 41 * mapping for a given key will not prevent the key from being discarded by the 42 * garbage collector, that is, made finalizable, finalized, and then reclaimed. 43 * When a key has been discarded its entry is effectively removed from the map, 44 * so this class behaves somewhat differently from other <tt>Map</tt> 45 * implementations. 46 * 47 * <p> Both null values and the null key are supported. This class has 48 * performance characteristics similar to those of the <tt>HashMap</tt> 49 * class, and has the same efficiency parameters of <em>initial capacity</em> 50 * and <em>load factor</em>. 51 * 52 * <p> Like most collection classes, this class is not synchronized. 53 * A synchronized <tt>WeakHashMap</tt> may be constructed using the 54 * {@link Collections#synchronizedMap Collections.synchronizedMap} 55 * method. 56 * 57 * <p> This class is intended primarily for use with key objects whose 58 * <tt>equals</tt> methods test for object identity using the 59 * <tt>==</tt> operator. Once such a key is discarded it can never be 60 * recreated, so it is impossible to do a lookup of that key in a 61 * <tt>WeakHashMap</tt> at some later time and be surprised that its entry 62 * has been removed. This class will work perfectly well with key objects 63 * whose <tt>equals</tt> methods are not based upon object identity, such 64 * as <tt>String</tt> instances. With such recreatable key objects, 65 * however, the automatic removal of <tt>WeakHashMap</tt> entries whose 66 * keys have been discarded may prove to be confusing. 67 * 68 * <p> The behavior of the <tt>WeakHashMap</tt> class depends in part upon 69 * the actions of the garbage collector, so several familiar (though not 70 * required) <tt>Map</tt> invariants do not hold for this class. Because 71 * the garbage collector may discard keys at any time, a 72 * <tt>WeakHashMap</tt> may behave as though an unknown thread is silently 73 * removing entries. In particular, even if you synchronize on a 74 * <tt>WeakHashMap</tt> instance and invoke none of its mutator methods, it 75 * is possible for the <tt>size</tt> method to return smaller values over 76 * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and 77 * then <tt>true</tt>, for the <tt>containsKey</tt> method to return 78 * <tt>true</tt> and later <tt>false</tt> for a given key, for the 79 * <tt>get</tt> method to return a value for a given key but later return 80 * <tt>null</tt>, for the <tt>put</tt> method to return 81 * <tt>null</tt> and the <tt>remove</tt> method to return 82 * <tt>false</tt> for a key that previously appeared to be in the map, and 83 * for successive examinations of the key set, the value collection, and 84 * the entry set to yield successively smaller numbers of elements. 85 * 86 * <p> Each key object in a <tt>WeakHashMap</tt> is stored indirectly as 87 * the referent of a weak reference. Therefore a key will automatically be 88 * removed only after the weak references to it, both inside and outside of the 89 * map, have been cleared by the garbage collector. 90 * 91 * <p> <strong>Implementation note:</strong> The value objects in a 92 * <tt>WeakHashMap</tt> are held by ordinary strong references. Thus care 93 * should be taken to ensure that value objects do not strongly refer to their 94 * own keys, either directly or indirectly, since that will prevent the keys 95 * from being discarded. Note that a value object may refer indirectly to its 96 * key via the <tt>WeakHashMap</tt> itself; that is, a value object may 97 * strongly refer to some other key object whose associated value object, in 98 * turn, strongly refers to the key of the first value object. If the values 99 * in the map do not rely on the map holding strong references to them, one way 100 * to deal with this is to wrap values themselves within 101 * <tt>WeakReferences</tt> before 102 * inserting, as in: <tt>m.put(key, new WeakReference(value))</tt>, 103 * and then unwrapping upon each <tt>get</tt>. 104 * 105 * <p>The iterators returned by the <tt>iterator</tt> method of the collections 106 * returned by all of this class's "collection view methods" are 107 * <i>fail-fast</i>: if the map is structurally modified at any time after the 108 * iterator is created, in any way except through the iterator's own 109 * <tt>remove</tt> method, the iterator will throw a {@link 110 * ConcurrentModificationException}. Thus, in the face of concurrent 111 * modification, the iterator fails quickly and cleanly, rather than risking 112 * arbitrary, non-deterministic behavior at an undetermined time in the future. 113 * 114 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 115 * as it is, generally speaking, impossible to make any hard guarantees in the 116 * presence of unsynchronized concurrent modification. Fail-fast iterators 117 * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. 118 * Therefore, it would be wrong to write a program that depended on this 119 * exception for its correctness: <i>the fail-fast behavior of iterators 120 * should be used only to detect bugs.</i> 121 * 122 * <p>This class is a member of the 123 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 124 * Java Collections Framework</a>. 125 * 126 * @param <K> the type of keys maintained by this map 127 * @param <V> the type of mapped values 128 * 129 * @author Doug Lea 130 * @author Josh Bloch 131 * @author Mark Reinhold 132 * @since 1.2 133 * @see java.util.HashMap 134 * @see java.lang.ref.WeakReference 135 */ 136 public class WeakHashMap<K,V> 137 extends AbstractMap<K,V> 179 */ 180 private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); 181 182 /** 183 * The number of times this WeakHashMap has been structurally modified. 184 * Structural modifications are those that change the number of 185 * mappings in the map or otherwise modify its internal structure 186 * (e.g., rehash). This field is used to make iterators on 187 * Collection-views of the map fail-fast. 188 * 189 * @see ConcurrentModificationException 190 */ 191 int modCount; 192 193 @SuppressWarnings("unchecked") 194 private Entry<K,V>[] newTable(int n) { 195 return (Entry<K,V>[]) new Entry<?,?>[n]; 196 } 197 198 /** 199 * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial 200 * capacity and the given load factor. 201 * 202 * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt> 203 * @param loadFactor The load factor of the <tt>WeakHashMap</tt> 204 * @throws IllegalArgumentException if the initial capacity is negative, 205 * or if the load factor is nonpositive. 206 */ 207 public WeakHashMap(int initialCapacity, float loadFactor) { 208 if (initialCapacity < 0) 209 throw new IllegalArgumentException("Illegal Initial Capacity: "+ 210 initialCapacity); 211 if (initialCapacity > MAXIMUM_CAPACITY) 212 initialCapacity = MAXIMUM_CAPACITY; 213 214 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 215 throw new IllegalArgumentException("Illegal Load factor: "+ 216 loadFactor); 217 int capacity = 1; 218 while (capacity < initialCapacity) 219 capacity <<= 1; 220 table = newTable(capacity); 221 this.loadFactor = loadFactor; 222 threshold = (int)(capacity * loadFactor); 223 } 224 225 /** 226 * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial 227 * capacity and the default load factor (0.75). 228 * 229 * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt> 230 * @throws IllegalArgumentException if the initial capacity is negative 231 */ 232 public WeakHashMap(int initialCapacity) { 233 this(initialCapacity, DEFAULT_LOAD_FACTOR); 234 } 235 236 /** 237 * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial 238 * capacity (16) and load factor (0.75). 239 */ 240 public WeakHashMap() { 241 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 242 } 243 244 /** 245 * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the 246 * specified map. The <tt>WeakHashMap</tt> is created with the default 247 * load factor (0.75) and an initial capacity sufficient to hold the 248 * mappings in the specified map. 249 * 250 * @param m the map whose mappings are to be placed in this map 251 * @throws NullPointerException if the specified map is null 252 * @since 1.3 253 */ 254 public WeakHashMap(Map<? extends K, ? extends V> m) { 255 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 256 DEFAULT_INITIAL_CAPACITY), 257 DEFAULT_LOAD_FACTOR); 258 putAll(m); 259 } 260 261 // internal utilities 262 263 /** 264 * Value representing null keys inside tables. 265 */ 266 private static final Object NULL_KEY = new Object(); 348 */ 349 private Entry<K,V>[] getTable() { 350 expungeStaleEntries(); 351 return table; 352 } 353 354 /** 355 * Returns the number of key-value mappings in this map. 356 * This result is a snapshot, and may not reflect unprocessed 357 * entries that will be removed before next attempted access 358 * because they are no longer referenced. 359 */ 360 public int size() { 361 if (size == 0) 362 return 0; 363 expungeStaleEntries(); 364 return size; 365 } 366 367 /** 368 * Returns <tt>true</tt> if this map contains no key-value mappings. 369 * This result is a snapshot, and may not reflect unprocessed 370 * entries that will be removed before next attempted access 371 * because they are no longer referenced. 372 */ 373 public boolean isEmpty() { 374 return size() == 0; 375 } 376 377 /** 378 * Returns the value to which the specified key is mapped, 379 * or {@code null} if this map contains no mapping for the key. 380 * 381 * <p>More formally, if this map contains a mapping from a key 382 * {@code k} to a value {@code v} such that {@code (key==null ? k==null : 383 * key.equals(k))}, then this method returns {@code v}; otherwise 384 * it returns {@code null}. (There can be at most one such mapping.) 385 * 386 * <p>A return value of {@code null} does not <i>necessarily</i> 387 * indicate that the map contains no mapping for the key; it's also 388 * possible that the map explicitly maps the key to {@code null}. 389 * The {@link #containsKey containsKey} operation may be used to 390 * distinguish these two cases. 391 * 392 * @see #put(Object, Object) 393 */ 394 public V get(Object key) { 395 Object k = maskNull(key); 396 int h = hash(k); 397 Entry<K,V>[] tab = getTable(); 398 int index = indexFor(h, tab.length); 399 Entry<K,V> e = tab[index]; 400 while (e != null) { 401 if (e.hash == h && eq(k, e.get())) 402 return e.value; 403 e = e.next; 404 } 405 return null; 406 } 407 408 /** 409 * Returns <tt>true</tt> if this map contains a mapping for the 410 * specified key. 411 * 412 * @param key The key whose presence in this map is to be tested 413 * @return <tt>true</tt> if there is a mapping for <tt>key</tt>; 414 * <tt>false</tt> otherwise 415 */ 416 public boolean containsKey(Object key) { 417 return getEntry(key) != null; 418 } 419 420 /** 421 * Returns the entry associated with the specified key in this map. 422 * Returns null if the map contains no mapping for this key. 423 */ 424 Entry<K,V> getEntry(Object key) { 425 Object k = maskNull(key); 426 int h = hash(k); 427 Entry<K,V>[] tab = getTable(); 428 int index = indexFor(h, tab.length); 429 Entry<K,V> e = tab[index]; 430 while (e != null && !(e.hash == h && eq(k, e.get()))) 431 e = e.next; 432 return e; 433 } 434 435 /** 436 * Associates the specified value with the specified key in this map. 437 * If the map previously contained a mapping for this key, the old 438 * value is replaced. 439 * 440 * @param key key with which the specified value is to be associated. 441 * @param value value to be associated with the specified key. 442 * @return the previous value associated with <tt>key</tt>, or 443 * <tt>null</tt> if there was no mapping for <tt>key</tt>. 444 * (A <tt>null</tt> return can also indicate that the map 445 * previously associated <tt>null</tt> with <tt>key</tt>.) 446 */ 447 public V put(K key, V value) { 448 Object k = maskNull(key); 449 int h = hash(k); 450 Entry<K,V>[] tab = getTable(); 451 int i = indexFor(h, tab.length); 452 453 for (Entry<K,V> e = tab[i]; e != null; e = e.next) { 454 if (h == e.hash && eq(k, e.get())) { 455 V oldValue = e.value; 456 if (value != oldValue) 457 e.value = value; 458 return oldValue; 459 } 460 } 461 462 modCount++; 463 Entry<K,V> e = tab[i]; 464 tab[i] = new Entry<>(k, value, queue, h, e); 465 if (++size >= threshold) 551 * By using the conservative calculation, we subject ourself 552 * to at most one extra resize. 553 */ 554 if (numKeysToBeAdded > threshold) { 555 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); 556 if (targetCapacity > MAXIMUM_CAPACITY) 557 targetCapacity = MAXIMUM_CAPACITY; 558 int newCapacity = table.length; 559 while (newCapacity < targetCapacity) 560 newCapacity <<= 1; 561 if (newCapacity > table.length) 562 resize(newCapacity); 563 } 564 565 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) 566 put(e.getKey(), e.getValue()); 567 } 568 569 /** 570 * Removes the mapping for a key from this weak hash map if it is present. 571 * More formally, if this map contains a mapping from key <tt>k</tt> to 572 * value <tt>v</tt> such that <code>(key==null ? k==null : 573 * key.equals(k))</code>, that mapping is removed. (The map can contain 574 * at most one such mapping.) 575 * 576 * <p>Returns the value to which this map previously associated the key, 577 * or <tt>null</tt> if the map contained no mapping for the key. A 578 * return value of <tt>null</tt> does not <i>necessarily</i> indicate 579 * that the map contained no mapping for the key; it's also possible 580 * that the map explicitly mapped the key to <tt>null</tt>. 581 * 582 * <p>The map will not contain a mapping for the specified key once the 583 * call returns. 584 * 585 * @param key key whose mapping is to be removed from the map 586 * @return the previous value associated with <tt>key</tt>, or 587 * <tt>null</tt> if there was no mapping for <tt>key</tt> 588 */ 589 public V remove(Object key) { 590 Object k = maskNull(key); 591 int h = hash(k); 592 Entry<K,V>[] tab = getTable(); 593 int i = indexFor(h, tab.length); 594 Entry<K,V> prev = tab[i]; 595 Entry<K,V> e = prev; 596 597 while (e != null) { 598 Entry<K,V> next = e.next; 599 if (h == e.hash && eq(k, e.get())) { 600 modCount++; 601 size--; 602 if (prev == e) 603 tab[i] = next; 604 else 605 prev.next = next; 606 return e.value; 607 } 647 * The map will be empty after this call returns. 648 */ 649 public void clear() { 650 // clear out ref queue. We don't need to expunge entries 651 // since table is getting cleared. 652 while (queue.poll() != null) 653 ; 654 655 modCount++; 656 Arrays.fill(table, null); 657 size = 0; 658 659 // Allocation of array may have caused GC, which may have caused 660 // additional entries to go stale. Removing these entries from the 661 // reference queue will make them eligible for reclamation. 662 while (queue.poll() != null) 663 ; 664 } 665 666 /** 667 * Returns <tt>true</tt> if this map maps one or more keys to the 668 * specified value. 669 * 670 * @param value value whose presence in this map is to be tested 671 * @return <tt>true</tt> if this map maps one or more keys to the 672 * specified value 673 */ 674 public boolean containsValue(Object value) { 675 if (value==null) 676 return containsNullValue(); 677 678 Entry<K,V>[] tab = getTable(); 679 for (int i = tab.length; i-- > 0;) 680 for (Entry<K,V> e = tab[i]; e != null; e = e.next) 681 if (value.equals(e.value)) 682 return true; 683 return false; 684 } 685 686 /** 687 * Special-case code for containsValue with null argument 688 */ 689 private boolean containsNullValue() { 690 Entry<K,V>[] tab = getTable(); 691 for (int i = tab.length; i-- > 0;) 838 public K next() { 839 return nextEntry().getKey(); 840 } 841 } 842 843 private class EntryIterator extends HashIterator<Map.Entry<K,V>> { 844 public Map.Entry<K,V> next() { 845 return nextEntry(); 846 } 847 } 848 849 // Views 850 851 private transient Set<Map.Entry<K,V>> entrySet; 852 853 /** 854 * Returns a {@link Set} view of the keys contained in this map. 855 * The set is backed by the map, so changes to the map are 856 * reflected in the set, and vice-versa. If the map is modified 857 * while an iteration over the set is in progress (except through 858 * the iterator's own <tt>remove</tt> operation), the results of 859 * the iteration are undefined. The set supports element removal, 860 * which removes the corresponding mapping from the map, via the 861 * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, 862 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> 863 * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> 864 * operations. 865 */ 866 public Set<K> keySet() { 867 Set<K> ks = keySet; 868 return (ks != null ? ks : (keySet = new KeySet())); 869 } 870 871 private class KeySet extends AbstractSet<K> { 872 public Iterator<K> iterator() { 873 return new KeyIterator(); 874 } 875 876 public int size() { 877 return WeakHashMap.this.size(); 878 } 879 880 public boolean contains(Object o) { 881 return containsKey(o); 882 } 883 887 return true; 888 } 889 else 890 return false; 891 } 892 893 public void clear() { 894 WeakHashMap.this.clear(); 895 } 896 897 public Spliterator<K> spliterator() { 898 return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0); 899 } 900 } 901 902 /** 903 * Returns a {@link Collection} view of the values contained in this map. 904 * The collection is backed by the map, so changes to the map are 905 * reflected in the collection, and vice-versa. If the map is 906 * modified while an iteration over the collection is in progress 907 * (except through the iterator's own <tt>remove</tt> operation), 908 * the results of the iteration are undefined. The collection 909 * supports element removal, which removes the corresponding 910 * mapping from the map, via the <tt>Iterator.remove</tt>, 911 * <tt>Collection.remove</tt>, <tt>removeAll</tt>, 912 * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not 913 * support the <tt>add</tt> or <tt>addAll</tt> operations. 914 */ 915 public Collection<V> values() { 916 Collection<V> vs = values; 917 return (vs != null) ? vs : (values = new Values()); 918 } 919 920 private class Values extends AbstractCollection<V> { 921 public Iterator<V> iterator() { 922 return new ValueIterator(); 923 } 924 925 public int size() { 926 return WeakHashMap.this.size(); 927 } 928 929 public boolean contains(Object o) { 930 return containsValue(o); 931 } 932 933 public void clear() { 934 WeakHashMap.this.clear(); 935 } 936 937 public Spliterator<V> spliterator() { 938 return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0); 939 } 940 } 941 942 /** 943 * Returns a {@link Set} view of the mappings contained in this map. 944 * The set is backed by the map, so changes to the map are 945 * reflected in the set, and vice-versa. If the map is modified 946 * while an iteration over the set is in progress (except through 947 * the iterator's own <tt>remove</tt> operation, or through the 948 * <tt>setValue</tt> operation on a map entry returned by the 949 * iterator) the results of the iteration are undefined. The set 950 * supports element removal, which removes the corresponding 951 * mapping from the map, via the <tt>Iterator.remove</tt>, 952 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and 953 * <tt>clear</tt> operations. It does not support the 954 * <tt>add</tt> or <tt>addAll</tt> operations. 955 */ 956 public Set<Map.Entry<K,V>> entrySet() { 957 Set<Map.Entry<K,V>> es = entrySet; 958 return es != null ? es : (entrySet = new EntrySet()); 959 } 960 961 private class EntrySet extends AbstractSet<Map.Entry<K,V>> { 962 public Iterator<Map.Entry<K,V>> iterator() { 963 return new EntryIterator(); 964 } 965 966 public boolean contains(Object o) { 967 if (!(o instanceof Map.Entry)) 968 return false; 969 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 970 Entry<K,V> candidate = getEntry(e.getKey()); 971 return candidate != null && candidate.equals(e); 972 } 973 974 public boolean remove(Object o) { | 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.lang.ref.WeakReference; 29 import java.lang.ref.ReferenceQueue; 30 import java.util.concurrent.ThreadLocalRandom; 31 import java.util.function.BiConsumer; 32 import java.util.function.BiFunction; 33 import java.util.function.Consumer; 34 35 36 /** 37 * Hash table based implementation of the {@code Map} interface, with 38 * <em>weak keys</em>. 39 * An entry in a {@code WeakHashMap} will automatically be removed when 40 * its key is no longer in ordinary use. More precisely, the presence of a 41 * mapping for a given key will not prevent the key from being discarded by the 42 * garbage collector, that is, made finalizable, finalized, and then reclaimed. 43 * When a key has been discarded its entry is effectively removed from the map, 44 * so this class behaves somewhat differently from other {@code Map} 45 * implementations. 46 * 47 * <p> Both null values and the null key are supported. This class has 48 * performance characteristics similar to those of the {@code HashMap} 49 * class, and has the same efficiency parameters of <em>initial capacity</em> 50 * and <em>load factor</em>. 51 * 52 * <p> Like most collection classes, this class is not synchronized. 53 * A synchronized {@code WeakHashMap} may be constructed using the 54 * {@link Collections#synchronizedMap Collections.synchronizedMap} 55 * method. 56 * 57 * <p> This class is intended primarily for use with key objects whose 58 * {@code equals} methods test for object identity using the 59 * {@code ==} operator. Once such a key is discarded it can never be 60 * recreated, so it is impossible to do a lookup of that key in a 61 * {@code WeakHashMap} at some later time and be surprised that its entry 62 * has been removed. This class will work perfectly well with key objects 63 * whose {@code equals} methods are not based upon object identity, such 64 * as {@code String} instances. With such recreatable key objects, 65 * however, the automatic removal of {@code WeakHashMap} entries whose 66 * keys have been discarded may prove to be confusing. 67 * 68 * <p> The behavior of the {@code WeakHashMap} class depends in part upon 69 * the actions of the garbage collector, so several familiar (though not 70 * required) {@code Map} invariants do not hold for this class. Because 71 * the garbage collector may discard keys at any time, a 72 * {@code WeakHashMap} may behave as though an unknown thread is silently 73 * removing entries. In particular, even if you synchronize on a 74 * {@code WeakHashMap} instance and invoke none of its mutator methods, it 75 * is possible for the {@code size} method to return smaller values over 76 * time, for the {@code isEmpty} method to return {@code false} and 77 * then {@code true}, for the {@code containsKey} method to return 78 * {@code true} and later {@code false} for a given key, for the 79 * {@code get} method to return a value for a given key but later return 80 * {@code null}, for the {@code put} method to return 81 * {@code null} and the {@code remove} method to return 82 * {@code false} for a key that previously appeared to be in the map, and 83 * for successive examinations of the key set, the value collection, and 84 * the entry set to yield successively smaller numbers of elements. 85 * 86 * <p> Each key object in a {@code WeakHashMap} is stored indirectly as 87 * the referent of a weak reference. Therefore a key will automatically be 88 * removed only after the weak references to it, both inside and outside of the 89 * map, have been cleared by the garbage collector. 90 * 91 * <p> <strong>Implementation note:</strong> The value objects in a 92 * {@code WeakHashMap} are held by ordinary strong references. Thus care 93 * should be taken to ensure that value objects do not strongly refer to their 94 * own keys, either directly or indirectly, since that will prevent the keys 95 * from being discarded. Note that a value object may refer indirectly to its 96 * key via the {@code WeakHashMap} itself; that is, a value object may 97 * strongly refer to some other key object whose associated value object, in 98 * turn, strongly refers to the key of the first value object. If the values 99 * in the map do not rely on the map holding strong references to them, one way 100 * to deal with this is to wrap values themselves within 101 * {@code WeakReferences} before 102 * inserting, as in: {@code m.put(key, new WeakReference(value))}, 103 * and then unwrapping upon each {@code get}. 104 * 105 * <p>The iterators returned by the {@code iterator} method of the collections 106 * returned by all of this class's "collection view methods" are 107 * <i>fail-fast</i>: if the map is structurally modified at any time after the 108 * iterator is created, in any way except through the iterator's own 109 * {@code remove} method, the iterator will throw a {@link 110 * ConcurrentModificationException}. Thus, in the face of concurrent 111 * modification, the iterator fails quickly and cleanly, rather than risking 112 * arbitrary, non-deterministic behavior at an undetermined time in the future. 113 * 114 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 115 * as it is, generally speaking, impossible to make any hard guarantees in the 116 * presence of unsynchronized concurrent modification. Fail-fast iterators 117 * throw {@code ConcurrentModificationException} on a best-effort basis. 118 * Therefore, it would be wrong to write a program that depended on this 119 * exception for its correctness: <i>the fail-fast behavior of iterators 120 * should be used only to detect bugs.</i> 121 * 122 * <p>This class is a member of the 123 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 124 * Java Collections Framework</a>. 125 * 126 * @param <K> the type of keys maintained by this map 127 * @param <V> the type of mapped values 128 * 129 * @author Doug Lea 130 * @author Josh Bloch 131 * @author Mark Reinhold 132 * @since 1.2 133 * @see java.util.HashMap 134 * @see java.lang.ref.WeakReference 135 */ 136 public class WeakHashMap<K,V> 137 extends AbstractMap<K,V> 179 */ 180 private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); 181 182 /** 183 * The number of times this WeakHashMap has been structurally modified. 184 * Structural modifications are those that change the number of 185 * mappings in the map or otherwise modify its internal structure 186 * (e.g., rehash). This field is used to make iterators on 187 * Collection-views of the map fail-fast. 188 * 189 * @see ConcurrentModificationException 190 */ 191 int modCount; 192 193 @SuppressWarnings("unchecked") 194 private Entry<K,V>[] newTable(int n) { 195 return (Entry<K,V>[]) new Entry<?,?>[n]; 196 } 197 198 /** 199 * Constructs a new, empty {@code WeakHashMap} with the given initial 200 * capacity and the given load factor. 201 * 202 * @param initialCapacity The initial capacity of the {@code WeakHashMap} 203 * @param loadFactor The load factor of the {@code WeakHashMap} 204 * @throws IllegalArgumentException if the initial capacity is negative, 205 * or if the load factor is nonpositive. 206 */ 207 public WeakHashMap(int initialCapacity, float loadFactor) { 208 if (initialCapacity < 0) 209 throw new IllegalArgumentException("Illegal Initial Capacity: "+ 210 initialCapacity); 211 if (initialCapacity > MAXIMUM_CAPACITY) 212 initialCapacity = MAXIMUM_CAPACITY; 213 214 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 215 throw new IllegalArgumentException("Illegal Load factor: "+ 216 loadFactor); 217 int capacity = 1; 218 while (capacity < initialCapacity) 219 capacity <<= 1; 220 table = newTable(capacity); 221 this.loadFactor = loadFactor; 222 threshold = (int)(capacity * loadFactor); 223 } 224 225 /** 226 * Constructs a new, empty {@code WeakHashMap} with the given initial 227 * capacity and the default load factor (0.75). 228 * 229 * @param initialCapacity The initial capacity of the {@code WeakHashMap} 230 * @throws IllegalArgumentException if the initial capacity is negative 231 */ 232 public WeakHashMap(int initialCapacity) { 233 this(initialCapacity, DEFAULT_LOAD_FACTOR); 234 } 235 236 /** 237 * Constructs a new, empty {@code WeakHashMap} with the default initial 238 * capacity (16) and load factor (0.75). 239 */ 240 public WeakHashMap() { 241 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 242 } 243 244 /** 245 * Constructs a new {@code WeakHashMap} with the same mappings as the 246 * specified map. The {@code WeakHashMap} is created with the default 247 * load factor (0.75) and an initial capacity sufficient to hold the 248 * mappings in the specified map. 249 * 250 * @param m the map whose mappings are to be placed in this map 251 * @throws NullPointerException if the specified map is null 252 * @since 1.3 253 */ 254 public WeakHashMap(Map<? extends K, ? extends V> m) { 255 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 256 DEFAULT_INITIAL_CAPACITY), 257 DEFAULT_LOAD_FACTOR); 258 putAll(m); 259 } 260 261 // internal utilities 262 263 /** 264 * Value representing null keys inside tables. 265 */ 266 private static final Object NULL_KEY = new Object(); 348 */ 349 private Entry<K,V>[] getTable() { 350 expungeStaleEntries(); 351 return table; 352 } 353 354 /** 355 * Returns the number of key-value mappings in this map. 356 * This result is a snapshot, and may not reflect unprocessed 357 * entries that will be removed before next attempted access 358 * because they are no longer referenced. 359 */ 360 public int size() { 361 if (size == 0) 362 return 0; 363 expungeStaleEntries(); 364 return size; 365 } 366 367 /** 368 * Returns {@code true} if this map contains no key-value mappings. 369 * This result is a snapshot, and may not reflect unprocessed 370 * entries that will be removed before next attempted access 371 * because they are no longer referenced. 372 */ 373 public boolean isEmpty() { 374 return size() == 0; 375 } 376 377 /** 378 * Returns the value to which the specified key is mapped, 379 * or {@code null} if this map contains no mapping for the key. 380 * 381 * <p>More formally, if this map contains a mapping from a key 382 * {@code k} to a value {@code v} such that {@code (key==null ? k==null : 383 * key.equals(k))}, then this method returns {@code v}; otherwise 384 * it returns {@code null}. (There can be at most one such mapping.) 385 * 386 * <p>A return value of {@code null} does not <i>necessarily</i> 387 * indicate that the map contains no mapping for the key; it's also 388 * possible that the map explicitly maps the key to {@code null}. 389 * The {@link #containsKey containsKey} operation may be used to 390 * distinguish these two cases. 391 * 392 * @see #put(Object, Object) 393 */ 394 public V get(Object key) { 395 Object k = maskNull(key); 396 int h = hash(k); 397 Entry<K,V>[] tab = getTable(); 398 int index = indexFor(h, tab.length); 399 Entry<K,V> e = tab[index]; 400 while (e != null) { 401 if (e.hash == h && eq(k, e.get())) 402 return e.value; 403 e = e.next; 404 } 405 return null; 406 } 407 408 /** 409 * Returns {@code true} if this map contains a mapping for the 410 * specified key. 411 * 412 * @param key The key whose presence in this map is to be tested 413 * @return {@code true} if there is a mapping for {@code key}; 414 * {@code false} otherwise 415 */ 416 public boolean containsKey(Object key) { 417 return getEntry(key) != null; 418 } 419 420 /** 421 * Returns the entry associated with the specified key in this map. 422 * Returns null if the map contains no mapping for this key. 423 */ 424 Entry<K,V> getEntry(Object key) { 425 Object k = maskNull(key); 426 int h = hash(k); 427 Entry<K,V>[] tab = getTable(); 428 int index = indexFor(h, tab.length); 429 Entry<K,V> e = tab[index]; 430 while (e != null && !(e.hash == h && eq(k, e.get()))) 431 e = e.next; 432 return e; 433 } 434 435 /** 436 * Associates the specified value with the specified key in this map. 437 * If the map previously contained a mapping for this key, the old 438 * value is replaced. 439 * 440 * @param key key with which the specified value is to be associated. 441 * @param value value to be associated with the specified key. 442 * @return the previous value associated with {@code key}, or 443 * {@code null} if there was no mapping for {@code key}. 444 * (A {@code null} return can also indicate that the map 445 * previously associated {@code null} with {@code key}.) 446 */ 447 public V put(K key, V value) { 448 Object k = maskNull(key); 449 int h = hash(k); 450 Entry<K,V>[] tab = getTable(); 451 int i = indexFor(h, tab.length); 452 453 for (Entry<K,V> e = tab[i]; e != null; e = e.next) { 454 if (h == e.hash && eq(k, e.get())) { 455 V oldValue = e.value; 456 if (value != oldValue) 457 e.value = value; 458 return oldValue; 459 } 460 } 461 462 modCount++; 463 Entry<K,V> e = tab[i]; 464 tab[i] = new Entry<>(k, value, queue, h, e); 465 if (++size >= threshold) 551 * By using the conservative calculation, we subject ourself 552 * to at most one extra resize. 553 */ 554 if (numKeysToBeAdded > threshold) { 555 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); 556 if (targetCapacity > MAXIMUM_CAPACITY) 557 targetCapacity = MAXIMUM_CAPACITY; 558 int newCapacity = table.length; 559 while (newCapacity < targetCapacity) 560 newCapacity <<= 1; 561 if (newCapacity > table.length) 562 resize(newCapacity); 563 } 564 565 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) 566 put(e.getKey(), e.getValue()); 567 } 568 569 /** 570 * Removes the mapping for a key from this weak hash map if it is present. 571 * More formally, if this map contains a mapping from key {@code k} to 572 * value {@code v} such that <code>(key==null ? k==null : 573 * key.equals(k))</code>, that mapping is removed. (The map can contain 574 * at most one such mapping.) 575 * 576 * <p>Returns the value to which this map previously associated the key, 577 * or {@code null} if the map contained no mapping for the key. A 578 * return value of {@code null} does not <i>necessarily</i> indicate 579 * that the map contained no mapping for the key; it's also possible 580 * that the map explicitly mapped the key to {@code null}. 581 * 582 * <p>The map will not contain a mapping for the specified key once the 583 * call returns. 584 * 585 * @param key key whose mapping is to be removed from the map 586 * @return the previous value associated with {@code key}, or 587 * {@code null} if there was no mapping for {@code key} 588 */ 589 public V remove(Object key) { 590 Object k = maskNull(key); 591 int h = hash(k); 592 Entry<K,V>[] tab = getTable(); 593 int i = indexFor(h, tab.length); 594 Entry<K,V> prev = tab[i]; 595 Entry<K,V> e = prev; 596 597 while (e != null) { 598 Entry<K,V> next = e.next; 599 if (h == e.hash && eq(k, e.get())) { 600 modCount++; 601 size--; 602 if (prev == e) 603 tab[i] = next; 604 else 605 prev.next = next; 606 return e.value; 607 } 647 * The map will be empty after this call returns. 648 */ 649 public void clear() { 650 // clear out ref queue. We don't need to expunge entries 651 // since table is getting cleared. 652 while (queue.poll() != null) 653 ; 654 655 modCount++; 656 Arrays.fill(table, null); 657 size = 0; 658 659 // Allocation of array may have caused GC, which may have caused 660 // additional entries to go stale. Removing these entries from the 661 // reference queue will make them eligible for reclamation. 662 while (queue.poll() != null) 663 ; 664 } 665 666 /** 667 * Returns {@code true} if this map maps one or more keys to the 668 * specified value. 669 * 670 * @param value value whose presence in this map is to be tested 671 * @return {@code true} if this map maps one or more keys to the 672 * specified value 673 */ 674 public boolean containsValue(Object value) { 675 if (value==null) 676 return containsNullValue(); 677 678 Entry<K,V>[] tab = getTable(); 679 for (int i = tab.length; i-- > 0;) 680 for (Entry<K,V> e = tab[i]; e != null; e = e.next) 681 if (value.equals(e.value)) 682 return true; 683 return false; 684 } 685 686 /** 687 * Special-case code for containsValue with null argument 688 */ 689 private boolean containsNullValue() { 690 Entry<K,V>[] tab = getTable(); 691 for (int i = tab.length; i-- > 0;) 838 public K next() { 839 return nextEntry().getKey(); 840 } 841 } 842 843 private class EntryIterator extends HashIterator<Map.Entry<K,V>> { 844 public Map.Entry<K,V> next() { 845 return nextEntry(); 846 } 847 } 848 849 // Views 850 851 private transient Set<Map.Entry<K,V>> entrySet; 852 853 /** 854 * Returns a {@link Set} view of the keys contained in this map. 855 * The set is backed by the map, so changes to the map are 856 * reflected in the set, and vice-versa. If the map is modified 857 * while an iteration over the set is in progress (except through 858 * the iterator's own {@code remove} operation), the results of 859 * the iteration are undefined. The set supports element removal, 860 * which removes the corresponding mapping from the map, via the 861 * {@code Iterator.remove}, {@code Set.remove}, 862 * {@code removeAll}, {@code retainAll}, and {@code clear} 863 * operations. It does not support the {@code add} or {@code addAll} 864 * operations. 865 */ 866 public Set<K> keySet() { 867 Set<K> ks = keySet; 868 return (ks != null ? ks : (keySet = new KeySet())); 869 } 870 871 private class KeySet extends AbstractSet<K> { 872 public Iterator<K> iterator() { 873 return new KeyIterator(); 874 } 875 876 public int size() { 877 return WeakHashMap.this.size(); 878 } 879 880 public boolean contains(Object o) { 881 return containsKey(o); 882 } 883 887 return true; 888 } 889 else 890 return false; 891 } 892 893 public void clear() { 894 WeakHashMap.this.clear(); 895 } 896 897 public Spliterator<K> spliterator() { 898 return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0); 899 } 900 } 901 902 /** 903 * Returns a {@link Collection} view of the values contained in this map. 904 * The collection is backed by the map, so changes to the map are 905 * reflected in the collection, and vice-versa. If the map is 906 * modified while an iteration over the collection is in progress 907 * (except through the iterator's own {@code remove} operation), 908 * the results of the iteration are undefined. The collection 909 * supports element removal, which removes the corresponding 910 * mapping from the map, via the {@code Iterator.remove}, 911 * {@code Collection.remove}, {@code removeAll}, 912 * {@code retainAll} and {@code clear} operations. It does not 913 * support the {@code add} or {@code addAll} operations. 914 */ 915 public Collection<V> values() { 916 Collection<V> vs = values; 917 return (vs != null) ? vs : (values = new Values()); 918 } 919 920 private class Values extends AbstractCollection<V> { 921 public Iterator<V> iterator() { 922 return new ValueIterator(); 923 } 924 925 public int size() { 926 return WeakHashMap.this.size(); 927 } 928 929 public boolean contains(Object o) { 930 return containsValue(o); 931 } 932 933 public void clear() { 934 WeakHashMap.this.clear(); 935 } 936 937 public Spliterator<V> spliterator() { 938 return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0); 939 } 940 } 941 942 /** 943 * Returns a {@link Set} view of the mappings contained in this map. 944 * The set is backed by the map, so changes to the map are 945 * reflected in the set, and vice-versa. If the map is modified 946 * while an iteration over the set is in progress (except through 947 * the iterator's own {@code remove} operation, or through the 948 * {@code setValue} operation on a map entry returned by the 949 * iterator) the results of the iteration are undefined. The set 950 * supports element removal, which removes the corresponding 951 * mapping from the map, via the {@code Iterator.remove}, 952 * {@code Set.remove}, {@code removeAll}, {@code retainAll} and 953 * {@code clear} operations. It does not support the 954 * {@code add} or {@code addAll} operations. 955 */ 956 public Set<Map.Entry<K,V>> entrySet() { 957 Set<Map.Entry<K,V>> es = entrySet; 958 return es != null ? es : (entrySet = new EntrySet()); 959 } 960 961 private class EntrySet extends AbstractSet<Map.Entry<K,V>> { 962 public Iterator<Map.Entry<K,V>> iterator() { 963 return new EntryIterator(); 964 } 965 966 public boolean contains(Object o) { 967 if (!(o instanceof Map.Entry)) 968 return false; 969 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 970 Entry<K,V> candidate = getEntry(e.getKey()); 971 return candidate != null && candidate.equals(e); 972 } 973 974 public boolean remove(Object o) { |