Source for java.util.WeakHashMap

   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