Frames | No Frames |
1: /* WeakHashMap -- a hashtable that keeps only weak references 2: to its keys, allowing the virtual machine to reclaim them 3: Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.util; 41: 42: import java.lang.ref.ReferenceQueue; 43: import java.lang.ref.WeakReference; 44: 45: /** 46: * A weak hash map has only weak references to the key. This means that it 47: * allows the key to be garbage collected if it is not used otherwise. If 48: * this happens, the entry will eventually disappear from the map, 49: * asynchronously. 50: * 51: * <p>A weak hash map makes most sense when the keys doesn't override the 52: * <code>equals</code> method: If there is no other reference to the 53: * key nobody can ever look up the key in this table and so the entry 54: * can be removed. This table also works when the <code>equals</code> 55: * method is overloaded, such as String keys, but you should be prepared 56: * to deal with some entries disappearing spontaneously. 57: * 58: * <p>Other strange behaviors to be aware of: The size of this map may 59: * spontaneously shrink (even if you use a synchronized map and synchronize 60: * it); it behaves as if another thread removes entries from this table 61: * without synchronization. The entry set returned by <code>entrySet</code> 62: * has similar phenomenons: The size may spontaneously shrink, or an 63: * entry, that was in the set before, suddenly disappears. 64: * 65: * <p>A weak hash map is not meant for caches; use a normal map, with 66: * soft references as values instead, or try {@link LinkedHashMap}. 67: * 68: * <p>The weak hash map supports null values and null keys. The null key 69: * is never deleted from the map (except explictly of course). The 70: * performance of the methods are similar to that of a hash map. 71: * 72: * <p>The value objects are strongly referenced by this table. So if a 73: * value object maintains a strong reference to the key (either direct 74: * or indirect) the key will never be removed from this map. According 75: * to Sun, this problem may be fixed in a future release. It is not 76: * possible to do it with the jdk 1.2 reference model, though. 77: * 78: * @author Jochen Hoenicke 79: * @author Eric Blake (ebb9@email.byu.edu) 80: * @author Tom Tromey (tromey@redhat.com) 81: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 82: * 83: * @see HashMap 84: * @see WeakReference 85: * @see LinkedHashMap 86: * @since 1.2 87: * @status updated to 1.4 (partial 1.5) 88: */ 89: public class WeakHashMap<K,V> extends AbstractMap<K,V> 90: { 91: // WARNING: WeakHashMap is a CORE class in the bootstrap cycle. See the 92: // comments in vm/reference/java/lang/Runtime for implications of this fact. 93: 94: /** 95: * The default capacity for an instance of HashMap. 96: * Sun's documentation mildly suggests that this (11) is the correct 97: * value. 98: */ 99: private static final int DEFAULT_CAPACITY = 11; 100: 101: /** 102: * The default load factor of a HashMap. 103: */ 104: private static final float DEFAULT_LOAD_FACTOR = 0.75F; 105: 106: /** 107: * This is used instead of the key value <i>null</i>. It is needed 108: * to distinguish between an null key and a removed key. 109: */ 110: // Package visible for use by nested classes. 111: static final Object NULL_KEY = new Object() 112: { 113: /** 114: * Sets the hashCode to 0, since that's what null would map to. 115: * @return the hash code 0 116: */ 117: public int hashCode() 118: { 119: return 0; 120: } 121: 122: /** 123: * Compares this key to the given object. Normally, an object should 124: * NEVER compare equal to null, but since we don't publicize NULL_VALUE, 125: * it saves bytecode to do so here. 126: * @return true iff o is this or null 127: */ 128: public boolean equals(Object o) 129: { 130: return null == o || this == o; 131: } 132: }; 133: 134: /** 135: * The reference queue where our buckets (which are WeakReferences) are 136: * registered to. 137: */ 138: private final ReferenceQueue queue; 139: 140: /** 141: * The number of entries in this hash map. 142: */ 143: // Package visible for use by nested classes. 144: int size; 145: 146: /** 147: * The load factor of this WeakHashMap. This is the maximum ratio of 148: * size versus number of buckets. If size grows the number of buckets 149: * must grow, too. 150: */ 151: private float loadFactor; 152: 153: /** 154: * The rounded product of the capacity (i.e. number of buckets) and 155: * the load factor. When the number of elements exceeds the 156: * threshold, the HashMap calls <code>rehash()</code>. 157: */ 158: private int threshold; 159: 160: /** 161: * The number of structural modifications. This is used by 162: * iterators, to see if they should fail. This doesn't count 163: * the silent key removals, when a weak reference is cleared 164: * by the garbage collection. Instead the iterators must make 165: * sure to have strong references to the entries they rely on. 166: */ 167: // Package visible for use by nested classes. 168: int modCount; 169: 170: /** 171: * The entry set. There is only one instance per hashmap, namely 172: * theEntrySet. Note that the entry set may silently shrink, just 173: * like the WeakHashMap. 174: */ 175: private final class WeakEntrySet extends AbstractSet 176: { 177: /** 178: * Non-private constructor to reduce bytecode emitted. 179: */ 180: WeakEntrySet() 181: { 182: } 183: 184: /** 185: * Returns the size of this set. 186: * 187: * @return the set size 188: */ 189: public int size() 190: { 191: return size; 192: } 193: 194: /** 195: * Returns an iterator for all entries. 196: * 197: * @return an Entry iterator 198: */ 199: public Iterator iterator() 200: { 201: return new Iterator() 202: { 203: /** 204: * The entry that was returned by the last 205: * <code>next()</code> call. This is also the entry whose 206: * bucket should be removed by the <code>remove</code> call. <br> 207: * 208: * It is null, if the <code>next</code> method wasn't 209: * called yet, or if the entry was already removed. <br> 210: * 211: * Remembering this entry here will also prevent it from 212: * being removed under us, since the entry strongly refers 213: * to the key. 214: */ 215: WeakBucket.WeakEntry lastEntry; 216: 217: /** 218: * The entry that will be returned by the next 219: * <code>next()</code> call. It is <code>null</code> if there 220: * is no further entry. <br> 221: * 222: * Remembering this entry here will also prevent it from 223: * being removed under us, since the entry strongly refers 224: * to the key. 225: */ 226: WeakBucket.WeakEntry nextEntry = findNext(null); 227: 228: /** 229: * The known number of modification to the list, if it differs 230: * from the real number, we throw an exception. 231: */ 232: int knownMod = modCount; 233: 234: /** 235: * Check the known number of modification to the number of 236: * modifications of the table. If it differs from the real 237: * number, we throw an exception. 238: * @throws ConcurrentModificationException if the number 239: * of modifications doesn't match. 240: */ 241: private void checkMod() 242: { 243: // This method will get inlined. 244: cleanQueue(); 245: if (knownMod != modCount) 246: throw new ConcurrentModificationException(knownMod + " != " 247: + modCount); 248: } 249: 250: /** 251: * Get a strong reference to the next entry after 252: * lastBucket. 253: * @param lastEntry the previous bucket, or null if we should 254: * get the first entry. 255: * @return the next entry. 256: */ 257: private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry) 258: { 259: int slot; 260: WeakBucket nextBucket; 261: if (lastEntry != null) 262: { 263: nextBucket = lastEntry.getBucket().next; 264: slot = lastEntry.getBucket().slot; 265: } 266: else 267: { 268: nextBucket = buckets[0]; 269: slot = 0; 270: } 271: 272: while (true) 273: { 274: while (nextBucket != null) 275: { 276: WeakBucket.WeakEntry entry = nextBucket.getEntry(); 277: if (entry != null) 278: // This is the next entry. 279: return entry; 280: 281: // Entry was cleared, try next. 282: nextBucket = nextBucket.next; 283: } 284: 285: slot++; 286: if (slot == buckets.length) 287: // No more buckets, we are through. 288: return null; 289: 290: nextBucket = buckets[slot]; 291: } 292: } 293: 294: /** 295: * Checks if there are more entries. 296: * @return true, iff there are more elements. 297: */ 298: public boolean hasNext() 299: { 300: return nextEntry != null; 301: } 302: 303: /** 304: * Returns the next entry. 305: * @return the next entry. 306: * @throws ConcurrentModificationException if the hash map was 307: * modified. 308: * @throws NoSuchElementException if there is no entry. 309: */ 310: public Object next() 311: { 312: checkMod(); 313: if (nextEntry == null) 314: throw new NoSuchElementException(); 315: lastEntry = nextEntry; 316: nextEntry = findNext(lastEntry); 317: return lastEntry; 318: } 319: 320: /** 321: * Removes the last returned entry from this set. This will 322: * also remove the bucket of the underlying weak hash map. 323: * @throws ConcurrentModificationException if the hash map was 324: * modified. 325: * @throws IllegalStateException if <code>next()</code> was 326: * never called or the element was already removed. 327: */ 328: public void remove() 329: { 330: checkMod(); 331: if (lastEntry == null) 332: throw new IllegalStateException(); 333: modCount++; 334: internalRemove(lastEntry.getBucket()); 335: lastEntry = null; 336: knownMod++; 337: } 338: }; 339: } 340: } 341: 342: /** 343: * A bucket is a weak reference to the key, that contains a strong 344: * reference to the value, a pointer to the next bucket and its slot 345: * number. <br> 346: * 347: * It would be cleaner to have a WeakReference as field, instead of 348: * extending it, but if a weak reference gets cleared, we only get 349: * the weak reference (by queue.poll) and wouldn't know where to 350: * look for this reference in the hashtable, to remove that entry. 351: * 352: * @author Jochen Hoenicke 353: */ 354: private static class WeakBucket<K, V> extends WeakReference<K> 355: { 356: /** 357: * The value of this entry. The key is stored in the weak 358: * reference that we extend. 359: */ 360: V value; 361: 362: /** 363: * The next bucket describing another entry that uses the same 364: * slot. 365: */ 366: WeakBucket<K, V> next; 367: 368: /** 369: * The slot of this entry. This should be 370: * <code>Math.abs(key.hashCode() % buckets.length)</code>. 371: * 372: * But since the key may be silently removed we have to remember 373: * the slot number. 374: * 375: * If this bucket was removed the slot is -1. This marker will 376: * prevent the bucket from being removed twice. 377: */ 378: int slot; 379: 380: /** 381: * Creates a new bucket for the given key/value pair and the specified 382: * slot. 383: * @param key the key 384: * @param queue the queue the weak reference belongs to 385: * @param value the value 386: * @param slot the slot. This must match the slot where this bucket 387: * will be enqueued. 388: */ 389: public WeakBucket(K key, ReferenceQueue queue, V value, 390: int slot) 391: { 392: super(key, queue); 393: this.value = value; 394: this.slot = slot; 395: } 396: 397: /** 398: * This class gives the <code>Entry</code> representation of the 399: * current bucket. It also keeps a strong reference to the 400: * key; bad things may happen otherwise. 401: */ 402: class WeakEntry implements Map.Entry<K, V> 403: { 404: /** 405: * The strong ref to the key. 406: */ 407: K key; 408: 409: /** 410: * Creates a new entry for the key. 411: * @param key the key 412: */ 413: public WeakEntry(K key) 414: { 415: this.key = key; 416: } 417: 418: /** 419: * Returns the underlying bucket. 420: * @return the owning bucket 421: */ 422: public WeakBucket getBucket() 423: { 424: return WeakBucket.this; 425: } 426: 427: /** 428: * Returns the key. 429: * @return the key 430: */ 431: public K getKey() 432: { 433: return key == NULL_KEY ? null : key; 434: } 435: 436: /** 437: * Returns the value. 438: * @return the value 439: */ 440: public V getValue() 441: { 442: return value; 443: } 444: 445: /** 446: * This changes the value. This change takes place in 447: * the underlying hash map. 448: * @param newVal the new value 449: * @return the old value 450: */ 451: public V setValue(V newVal) 452: { 453: V oldVal = value; 454: value = newVal; 455: return oldVal; 456: } 457: 458: /** 459: * The hashCode as specified in the Entry interface. 460: * @return the hash code 461: */ 462: public int hashCode() 463: { 464: return key.hashCode() ^ WeakHashMap.hashCode(value); 465: } 466: 467: /** 468: * The equals method as specified in the Entry interface. 469: * @param o the object to compare to 470: * @return true iff o represents the same key/value pair 471: */ 472: public boolean equals(Object o) 473: { 474: if (o instanceof Map.Entry) 475: { 476: Map.Entry e = (Map.Entry) o; 477: return WeakHashMap.equals(getKey(), e.getKey()) 478: && WeakHashMap.equals(value, e.getValue()); 479: } 480: return false; 481: } 482: 483: public String toString() 484: { 485: return getKey() + "=" + value; 486: } 487: } 488: 489: /** 490: * This returns the entry stored in this bucket, or null, if the 491: * bucket got cleared in the mean time. 492: * @return the Entry for this bucket, if it exists 493: */ 494: WeakEntry getEntry() 495: { 496: final K key = this.get(); 497: if (key == null) 498: return null; 499: return new WeakEntry(key); 500: } 501: } 502: 503: /** 504: * The entry set returned by <code>entrySet()</code>. 505: */ 506: private final WeakEntrySet theEntrySet; 507: 508: /** 509: * The hash buckets. These are linked lists. Package visible for use in 510: * nested classes. 511: */ 512: WeakBucket[] buckets; 513: 514: /** 515: * Creates a new weak hash map with default load factor and default 516: * capacity. 517: */ 518: public WeakHashMap() 519: { 520: this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); 521: } 522: 523: /** 524: * Creates a new weak hash map with default load factor and the given 525: * capacity. 526: * @param initialCapacity the initial capacity 527: * @throws IllegalArgumentException if initialCapacity is negative 528: */ 529: public WeakHashMap(int initialCapacity) 530: { 531: this(initialCapacity, DEFAULT_LOAD_FACTOR); 532: } 533: 534: /** 535: * Creates a new weak hash map with the given initial capacity and 536: * load factor. 537: * @param initialCapacity the initial capacity. 538: * @param loadFactor the load factor (see class description of HashMap). 539: * @throws IllegalArgumentException if initialCapacity is negative, or 540: * loadFactor is non-positive 541: */ 542: public WeakHashMap(int initialCapacity, float loadFactor) 543: { 544: // Check loadFactor for NaN as well. 545: if (initialCapacity < 0 || ! (loadFactor > 0)) 546: throw new IllegalArgumentException(); 547: if (initialCapacity == 0) 548: initialCapacity = 1; 549: this.loadFactor = loadFactor; 550: threshold = (int) (initialCapacity * loadFactor); 551: theEntrySet = new WeakEntrySet(); 552: queue = new ReferenceQueue(); 553: buckets = new WeakBucket[initialCapacity]; 554: } 555: 556: /** 557: * Construct a new WeakHashMap with the same mappings as the given map. 558: * The WeakHashMap has a default load factor of 0.75. 559: * 560: * @param m the map to copy 561: * @throws NullPointerException if m is null 562: * @since 1.3 563: */ 564: public WeakHashMap(Map<? extends K, ? extends V> m) 565: { 566: this(m.size(), DEFAULT_LOAD_FACTOR); 567: putAll(m); 568: } 569: 570: /** 571: * Simply hashes a non-null Object to its array index. 572: * @param key the key to hash 573: * @return its slot number 574: */ 575: private int hash(Object key) 576: { 577: return Math.abs(key.hashCode() % buckets.length); 578: } 579: 580: /** 581: * Cleans the reference queue. This will poll all references (which 582: * are WeakBuckets) from the queue and remove them from this map. 583: * This will not change modCount, even if it modifies the map. The 584: * iterators have to make sure that nothing bad happens. <br> 585: * 586: * Currently the iterator maintains a strong reference to the key, so 587: * that is no problem. 588: */ 589: // Package visible for use by nested classes. 590: void cleanQueue() 591: { 592: Object bucket = queue.poll(); 593: while (bucket != null) 594: { 595: internalRemove((WeakBucket) bucket); 596: bucket = queue.poll(); 597: } 598: } 599: 600: /** 601: * Rehashes this hashtable. This will be called by the 602: * <code>add()</code> method if the size grows beyond the threshold. 603: * It will grow the bucket size at least by factor two and allocates 604: * new buckets. 605: */ 606: private void rehash() 607: { 608: WeakBucket[] oldBuckets = buckets; 609: int newsize = buckets.length * 2 + 1; // XXX should be prime. 610: threshold = (int) (newsize * loadFactor); 611: buckets = new WeakBucket[newsize]; 612: 613: // Now we have to insert the buckets again. 614: for (int i = 0; i < oldBuckets.length; i++) 615: { 616: WeakBucket bucket = oldBuckets[i]; 617: WeakBucket nextBucket; 618: while (bucket != null) 619: { 620: nextBucket = bucket.next; 621: 622: Object key = bucket.get(); 623: if (key == null) 624: { 625: // This bucket should be removed; it is probably 626: // already on the reference queue. We don't insert it 627: // at all, and mark it as cleared. 628: bucket.slot = -1; 629: size--; 630: } 631: else 632: { 633: // Add this bucket to its new slot. 634: int slot = hash(key); 635: bucket.slot = slot; 636: bucket.next = buckets[slot]; 637: buckets[slot] = bucket; 638: } 639: bucket = nextBucket; 640: } 641: } 642: } 643: 644: /** 645: * Finds the entry corresponding to key. Since it returns an Entry 646: * it will also prevent the key from being removed under us. 647: * @param key the key, may be null 648: * @return The WeakBucket.WeakEntry or null, if the key wasn't found. 649: */ 650: private WeakBucket.WeakEntry internalGet(Object key) 651: { 652: if (key == null) 653: key = NULL_KEY; 654: int slot = hash(key); 655: WeakBucket bucket = buckets[slot]; 656: while (bucket != null) 657: { 658: WeakBucket.WeakEntry entry = bucket.getEntry(); 659: if (entry != null && equals(key, entry.key)) 660: return entry; 661: 662: bucket = bucket.next; 663: } 664: return null; 665: } 666: 667: /** 668: * Adds a new key/value pair to the hash map. 669: * @param key the key. This mustn't exists in the map. It may be null. 670: * @param value the value. 671: */ 672: private void internalAdd(Object key, Object value) 673: { 674: if (key == null) 675: key = NULL_KEY; 676: int slot = hash(key); 677: WeakBucket bucket = new WeakBucket(key, queue, value, slot); 678: bucket.next = buckets[slot]; 679: buckets[slot] = bucket; 680: size++; 681: } 682: 683: /** 684: * Removes a bucket from this hash map, if it wasn't removed before 685: * (e.g. one time through rehashing and one time through reference queue). 686: * Package visible for use in nested classes. 687: * 688: * @param bucket the bucket to remove. 689: */ 690: void internalRemove(WeakBucket bucket) 691: { 692: int slot = bucket.slot; 693: if (slot == -1) 694: // This bucket was already removed. 695: return; 696: 697: // Mark the bucket as removed. This is necessary, since the 698: // bucket may be enqueued later by the garbage collection, and 699: // internalRemove will be called a second time. 700: bucket.slot = -1; 701: 702: WeakBucket prev = null; 703: WeakBucket next = buckets[slot]; 704: while (next != bucket) 705: { 706: if (next == null) throw new InternalError("WeakHashMap in incosistent state"); 707: prev = next; 708: next = prev.next; 709: } 710: if (prev == null) 711: buckets[slot] = bucket.next; 712: else 713: prev.next = bucket.next; 714: 715: size--; 716: } 717: 718: /** 719: * Returns the size of this hash map. Note that the size() may shrink 720: * spontaneously, if the some of the keys were only weakly reachable. 721: * @return the number of entries in this hash map. 722: */ 723: public int size() 724: { 725: cleanQueue(); 726: return size; 727: } 728: 729: /** 730: * Tells if the map is empty. Note that the result may change 731: * spontanously, if all of the keys were only weakly reachable. 732: * @return true, iff the map is empty. 733: */ 734: public boolean isEmpty() 735: { 736: cleanQueue(); 737: return size == 0; 738: } 739: 740: /** 741: * Tells if the map contains the given key. Note that the result 742: * may change spontanously, if the key was only weakly 743: * reachable. 744: * @param key the key to look for 745: * @return true, iff the map contains an entry for the given key. 746: */ 747: public boolean containsKey(Object key) 748: { 749: cleanQueue(); 750: return internalGet(key) != null; 751: } 752: 753: /** 754: * Gets the value the key is mapped to. 755: * @return the value the key was mapped to. It returns null if 756: * the key wasn't in this map, or if the mapped value was 757: * explicitly set to null. 758: */ 759: public V get(Object key) 760: { 761: cleanQueue(); 762: WeakBucket<K, V>.WeakEntry entry = internalGet(key); 763: return entry == null ? null : entry.getValue(); 764: } 765: 766: /** 767: * Adds a new key/value mapping to this map. 768: * @param key the key, may be null 769: * @param value the value, may be null 770: * @return the value the key was mapped to previously. It returns 771: * null if the key wasn't in this map, or if the mapped value 772: * was explicitly set to null. 773: */ 774: public V put(K key, V value) 775: { 776: cleanQueue(); 777: WeakBucket<K, V>.WeakEntry entry = internalGet(key); 778: if (entry != null) 779: return entry.setValue(value); 780: 781: modCount++; 782: if (size >= threshold) 783: rehash(); 784: 785: internalAdd(key, value); 786: return null; 787: } 788: 789: /** 790: * Removes the key and the corresponding value from this map. 791: * @param key the key. This may be null. 792: * @return the value the key was mapped to previously. It returns 793: * null if the key wasn't in this map, or if the mapped value was 794: * explicitly set to null. 795: */ 796: public V remove(Object key) 797: { 798: cleanQueue(); 799: WeakBucket<K, V>.WeakEntry entry = internalGet(key); 800: if (entry == null) 801: return null; 802: 803: modCount++; 804: internalRemove(entry.getBucket()); 805: return entry.getValue(); 806: } 807: 808: /** 809: * Returns a set representation of the entries in this map. This 810: * set will not have strong references to the keys, so they can be 811: * silently removed. The returned set has therefore the same 812: * strange behaviour (shrinking size(), disappearing entries) as 813: * this weak hash map. 814: * @return a set representation of the entries. 815: */ 816: public Set<Map.Entry<K,V>> entrySet() 817: { 818: cleanQueue(); 819: return theEntrySet; 820: } 821: 822: /** 823: * Clears all entries from this map. 824: */ 825: public void clear() 826: { 827: super.clear(); 828: } 829: 830: /** 831: * Returns true if the map contains at least one key which points to 832: * the specified object as a value. Note that the result 833: * may change spontanously, if its key was only weakly reachable. 834: * @param value the value to search for 835: * @return true if it is found in the set. 836: */ 837: public boolean containsValue(Object value) 838: { 839: cleanQueue(); 840: return super.containsValue(value); 841: } 842: 843: /** 844: * Returns a set representation of the keys in this map. This 845: * set will not have strong references to the keys, so they can be 846: * silently removed. The returned set has therefore the same 847: * strange behaviour (shrinking size(), disappearing entries) as 848: * this weak hash map. 849: * @return a set representation of the keys. 850: */ 851: public Set<K> keySet() 852: { 853: cleanQueue(); 854: return super.keySet(); 855: } 856: 857: /** 858: * Puts all of the mappings from the given map into this one. If the 859: * key already exists in this map, its value is replaced. 860: * @param m the map to copy in 861: */ 862: public void putAll(Map<? extends K, ? extends V> m) 863: { 864: super.putAll(m); 865: } 866: 867: /** 868: * Returns a collection representation of the values in this map. This 869: * collection will not have strong references to the keys, so mappings 870: * can be silently removed. The returned collection has therefore the same 871: * strange behaviour (shrinking size(), disappearing entries) as 872: * this weak hash map. 873: * @return a collection representation of the values. 874: */ 875: public Collection<V> values() 876: { 877: cleanQueue(); 878: return super.values(); 879: } 880: } // class WeakHashMap