Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

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
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /