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