Source for java.util.AbstractMap

   1: /* AbstractMap.java -- Abstract implementation of most of Map
   2:    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005
   3:    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.io.Serializable;
  43: 
  44: /**
  45:  * An abstract implementation of Map to make it easier to create your own
  46:  * implementations. In order to create an unmodifiable Map, subclass
  47:  * AbstractMap and implement the <code>entrySet</code> (usually via an
  48:  * AbstractSet).  To make it modifiable, also implement <code>put</code>,
  49:  * and have <code>entrySet().iterator()</code> support <code>remove</code>.
  50:  * <p>
  51:  *
  52:  * It is recommended that classes which extend this support at least the
  53:  * no-argument constructor, and a constructor which accepts another Map.
  54:  * Further methods in this class may be overridden if you have a more
  55:  * efficient implementation.
  56:  *
  57:  * @author Original author unknown
  58:  * @author Bryce McKinlay
  59:  * @author Eric Blake (ebb9@email.byu.edu)
  60:  * @see Map
  61:  * @see Collection
  62:  * @see HashMap
  63:  * @see LinkedHashMap
  64:  * @see TreeMap
  65:  * @see WeakHashMap
  66:  * @see IdentityHashMap
  67:  * @since 1.2
  68:  * @status updated to 1.4
  69:  */
  70: public abstract class AbstractMap<K, V> implements Map<K, V>
  71: {
  72:   /** 
  73:    * A class containing an immutable key and value.  The
  74:    * implementation of {@link Entry#setValue(V)} for this class
  75:    * simply throws an {@link UnsupportedOperationException},
  76:    * thus preventing changes being made.  This is useful when
  77:    * a static thread-safe view of a map is required.
  78:    *
  79:    * @since 1.6 
  80:    */
  81:   public static class SimpleImmutableEntry<K, V>
  82:     implements Entry<K, V>, Serializable
  83:   {
  84:     /**
  85:      * Compatible with JDK 1.6
  86:      */
  87:     private static final long serialVersionUID = 7138329143949025153L;
  88: 
  89:     K key;
  90:     V value;
  91: 
  92:     public SimpleImmutableEntry(K key, V value)
  93:     {
  94:       this.key = key;
  95:       this.value = value;
  96:     }
  97: 
  98:     public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry)
  99:     {
 100:       this(entry.getKey(), entry.getValue());
 101:     }
 102: 
 103:     public K getKey()
 104:     {
 105:       return key;
 106:     }
 107: 
 108:     public V getValue()
 109:     {
 110:       return value;
 111:     }
 112: 
 113:     public V setValue(V value)
 114:     {
 115:       throw new UnsupportedOperationException("setValue not supported on immutable entry");
 116:     }
 117:   }
 118: 
 119: /** An "enum" of iterator types. */
 120:   // Package visible for use by subclasses.
 121:   static final int KEYS = 0,
 122:                    VALUES = 1,
 123:                    ENTRIES = 2;
 124: 
 125:   /**
 126:    * The cache for {@link #keySet()}.
 127:    */
 128:   // Package visible for use by subclasses.
 129:   Set<K> keys;
 130: 
 131:   /**
 132:    * The cache for {@link #values()}.
 133:    */
 134:   // Package visible for use by subclasses.
 135:   Collection<V> values;
 136: 
 137:   /**
 138:    * The main constructor, for use by subclasses.
 139:    */
 140:   protected AbstractMap()
 141:   {
 142:   }
 143: 
 144:   /**
 145:    * Returns a set view of the mappings in this Map.  Each element in the
 146:    * set must be an implementation of Map.Entry.  The set is backed by
 147:    * the map, so that changes in one show up in the other.  Modifications
 148:    * made while an iterator is in progress cause undefined behavior.  If
 149:    * the set supports removal, these methods must be valid:
 150:    * <code>Iterator.remove</code>, <code>Set.remove</code>,
 151:    * <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
 152:    * Element addition is not supported via this set.
 153:    *
 154:    * @return the entry set
 155:    * @see Map.Entry
 156:    */
 157:   public abstract Set<Map.Entry<K, V>> entrySet();
 158: 
 159:   /**
 160:    * Remove all entries from this Map (optional operation). This default
 161:    * implementation calls entrySet().clear(). NOTE: If the entry set does
 162:    * not permit clearing, then this will fail, too. Subclasses often
 163:    * override this for efficiency.  Your implementation of entrySet() should
 164:    * not call <code>AbstractMap.clear</code> unless you want an infinite loop.
 165:    *
 166:    * @throws UnsupportedOperationException if <code>entrySet().clear()</code>
 167:    *         does not support clearing.
 168:    * @see Set#clear()
 169:    */
 170:   public void clear()
 171:   {
 172:     entrySet().clear();
 173:   }
 174: 
 175:   /**
 176:    * Create a shallow copy of this Map, no keys or values are copied. The
 177:    * default implementation simply calls <code>super.clone()</code>.
 178:    *
 179:    * @return the shallow clone
 180:    * @throws CloneNotSupportedException if a subclass is not Cloneable
 181:    * @see Cloneable
 182:    * @see Object#clone()
 183:    */
 184:   protected Object clone() throws CloneNotSupportedException
 185:   {
 186:     AbstractMap<K, V> copy = (AbstractMap<K, V>) super.clone();
 187:     // Clear out the caches; they are stale.
 188:     copy.keys = null;
 189:     copy.values = null;
 190:     return copy;
 191:   }
 192: 
 193:   /**
 194:    * Returns true if this contains a mapping for the given key. This
 195:    * implementation does a linear search, O(n), over the
 196:    * <code>entrySet()</code>, returning <code>true</code> if a match
 197:    * is found, <code>false</code> if the iteration ends. Many subclasses
 198:    * can implement this more efficiently.
 199:    *
 200:    * @param key the key to search for
 201:    * @return true if the map contains the key
 202:    * @throws NullPointerException if key is <code>null</code> but the map
 203:    *         does not permit null keys
 204:    * @see #containsValue(Object)
 205:    */
 206:   public boolean containsKey(Object key)
 207:   {
 208:     Iterator<Map.Entry<K, V>> entries = entrySet().iterator();
 209:     int pos = size();
 210:     while (--pos >= 0)
 211:       if (equals(key, entries.next().getKey()))
 212:         return true;
 213:     return false;
 214:   }
 215: 
 216:   /**
 217:    * Returns true if this contains at least one mapping with the given value.
 218:    * This implementation does a linear search, O(n), over the
 219:    * <code>entrySet()</code>, returning <code>true</code> if a match
 220:    * is found, <code>false</code> if the iteration ends. A match is
 221:    * defined as a value, v, where <code>(value == null ? v == null :
 222:    * value.equals(v))</code>.  Subclasses are unlikely to implement
 223:    * this more efficiently.
 224:    *
 225:    * @param value the value to search for
 226:    * @return true if the map contains the value
 227:    * @see #containsKey(Object)
 228:    */
 229:   public boolean containsValue(Object value)
 230:   {
 231:     Iterator<Map.Entry<K, V>> entries = entrySet().iterator();
 232:     int pos = size();
 233:     while (--pos >= 0)
 234:       if (equals(value, entries.next().getValue()))
 235:         return true;
 236:     return false;
 237:   }
 238: 
 239:   /**
 240:    * Compares the specified object with this map for equality. Returns
 241:    * <code>true</code> if the other object is a Map with the same mappings,
 242:    * that is,<br>
 243:    * <code>o instanceof Map && entrySet().equals(((Map) o).entrySet();</code>
 244:    *
 245:    * @param o the object to be compared
 246:    * @return true if the object equals this map
 247:    * @see Set#equals(Object)
 248:    */
 249:   public boolean equals(Object o)
 250:   {
 251:     return (o == this
 252:         || (o instanceof Map
 253:         && entrySet().equals(((Map<K, V>) o).entrySet())));
 254:   }
 255: 
 256:   /**
 257:    * Returns the value mapped by the given key. Returns <code>null</code> if
 258:    * there is no mapping.  However, in Maps that accept null values, you
 259:    * must rely on <code>containsKey</code> to determine if a mapping exists.
 260:    * This iteration takes linear time, searching entrySet().iterator() of
 261:    * the key.  Many implementations override this method.
 262:    *
 263:    * @param key the key to look up
 264:    * @return the value associated with the key, or null if key not in map
 265:    * @throws NullPointerException if this map does not accept null keys
 266:    * @see #containsKey(Object)
 267:    */
 268:   public V get(Object key)
 269:   {
 270:     Iterator<Map.Entry<K, V>> entries = entrySet().iterator();
 271:     int pos = size();
 272:     while (--pos >= 0)
 273:       {
 274:         Map.Entry<K, V> entry = entries.next();
 275:         if (equals(key, entry.getKey()))
 276:           return entry.getValue();
 277:       }
 278:     return null;
 279:   }
 280: 
 281:   /**
 282:    * Returns the hash code for this map. As defined in Map, this is the sum
 283:    * of all hashcodes for each Map.Entry object in entrySet, or basically
 284:    * entrySet().hashCode().
 285:    *
 286:    * @return the hash code
 287:    * @see Map.Entry#hashCode()
 288:    * @see Set#hashCode()
 289:    */
 290:   public int hashCode()
 291:   {
 292:     return entrySet().hashCode();
 293:   }
 294: 
 295:   /**
 296:    * Returns true if the map contains no mappings. This is implemented by
 297:    * <code>size() == 0</code>.
 298:    *
 299:    * @return true if the map is empty
 300:    * @see #size()
 301:    */
 302:   public boolean isEmpty()
 303:   {
 304:     return size() == 0;
 305:   }
 306: 
 307:   /**
 308:    * Returns a set view of this map's keys. The set is backed by the map,
 309:    * so changes in one show up in the other. Modifications while an iteration
 310:    * is in progress produce undefined behavior. The set supports removal
 311:    * if entrySet() does, but does not support element addition.
 312:    * <p>
 313:    *
 314:    * This implementation creates an AbstractSet, where the iterator wraps
 315:    * the entrySet iterator, size defers to the Map's size, and contains
 316:    * defers to the Map's containsKey. The set is created on first use, and
 317:    * returned on subsequent uses, although since no synchronization occurs,
 318:    * there is a slight possibility of creating two sets.
 319:    *
 320:    * @return a Set view of the keys
 321:    * @see Set#iterator()
 322:    * @see #size()
 323:    * @see #containsKey(Object)
 324:    * @see #values()
 325:    */
 326:   public Set<K> keySet()
 327:   {
 328:     if (keys == null)
 329:       keys = new AbstractSet<K>()
 330:       {
 331:     /**
 332:      * Retrieves the number of keys in the backing map.
 333:      *
 334:      * @return The number of keys.
 335:      */
 336:         public int size()
 337:         {
 338:           return AbstractMap.this.size();
 339:         }
 340: 
 341:     /**
 342:      * Returns true if the backing map contains the
 343:      * supplied key.
 344:      *
 345:      * @param key The key to search for.
 346:      * @return True if the key was found, false otherwise.
 347:       */
 348:         public boolean contains(Object key)
 349:         {
 350:           return containsKey(key);
 351:         }
 352: 
 353:     /**
 354:      * Returns an iterator which iterates over the keys
 355:      * in the backing map, using a wrapper around the
 356:      * iterator returned by <code>entrySet()</code>.
 357:      *
 358:      * @return An iterator over the keys.
 359:      */
 360:         public Iterator<K> iterator()
 361:         {
 362:           return new Iterator<K>()
 363:           {
 364:         /**
 365:          * The iterator returned by <code>entrySet()</code>.
 366:          */
 367:             private final Iterator<Map.Entry<K, V>> map_iterator
 368:           = entrySet().iterator();
 369: 
 370:         /**
 371:          * Returns true if a call to <code>next()</code> will
 372:          * return another key.
 373:          *
 374:          * @return True if the iterator has not yet reached
 375:          *         the last key.
 376:          */
 377:             public boolean hasNext()
 378:             {
 379:               return map_iterator.hasNext();
 380:             }
 381: 
 382:         /**
 383:          * Returns the key from the next entry retrieved
 384:          * by the underlying <code>entrySet()</code> iterator.
 385:          *
 386:          * @return The next key.
 387:          */ 
 388:            public K next()
 389:             {
 390:               return map_iterator.next().getKey();
 391:             }
 392: 
 393:         /**
 394:          * Removes the map entry which has a key equal
 395:          * to that returned by the last call to
 396:          * <code>next()</code>.
 397:          *
 398:          * @throws UnsupportedOperationException if the
 399:          *         map doesn't support removal.
 400:          */
 401:             public void remove()
 402:             {
 403:               map_iterator.remove();
 404:             }
 405:           };
 406:         }
 407:       };
 408:     return keys;
 409:   }
 410: 
 411:   /**
 412:    * Associates the given key to the given value (optional operation). If the
 413:    * map already contains the key, its value is replaced. This implementation
 414:    * simply throws an UnsupportedOperationException. Be aware that in a map
 415:    * that permits <code>null</code> values, a null return does not always
 416:    * imply that the mapping was created.
 417:    *
 418:    * @param key the key to map
 419:    * @param value the value to be mapped
 420:    * @return the previous value of the key, or null if there was no mapping
 421:    * @throws UnsupportedOperationException if the operation is not supported
 422:    * @throws ClassCastException if the key or value is of the wrong type
 423:    * @throws IllegalArgumentException if something about this key or value
 424:    *         prevents it from existing in this map
 425:    * @throws NullPointerException if the map forbids null keys or values
 426:    * @see #containsKey(Object)
 427:    */
 428:   public V put(K key, V value)
 429:   {
 430:     throw new UnsupportedOperationException();
 431:   }
 432: 
 433:   /**
 434:    * Copies all entries of the given map to this one (optional operation). If
 435:    * the map already contains a key, its value is replaced. This implementation
 436:    * simply iterates over the map's entrySet(), calling <code>put</code>,
 437:    * so it is not supported if puts are not.
 438:    *
 439:    * @param m the mapping to load into this map
 440:    * @throws UnsupportedOperationException if the operation is not supported
 441:    *         by this map.
 442:    * @throws ClassCastException if a key or value is of the wrong type for
 443:    *         adding to this map.
 444:    * @throws IllegalArgumentException if something about a key or value
 445:    *         prevents it from existing in this map.
 446:    * @throws NullPointerException if the map forbids null keys or values.
 447:    * @throws NullPointerException if <code>m</code> is null.
 448:    * @see #put(Object, Object)
 449:    */
 450:   public void putAll(Map<? extends K, ? extends V> m)
 451:   {
 452:     // FIXME: bogus circumlocution.
 453:     Iterator entries2 = m.entrySet().iterator();
 454:     Iterator<Map.Entry<? extends K, ? extends V>> entries
 455:       = (Iterator<Map.Entry<? extends K, ? extends V>>) entries2;
 456:     int pos = m.size();
 457:     while (--pos >= 0)
 458:       {
 459:         Map.Entry<? extends K, ? extends V> entry = entries.next();
 460:         put(entry.getKey(), entry.getValue());
 461:       }
 462:   }
 463: 
 464:   /**
 465:    * Removes the mapping for this key if present (optional operation). This
 466:    * implementation iterates over the entrySet searching for a matching
 467:    * key, at which point it calls the iterator's <code>remove</code> method.
 468:    * It returns the result of <code>getValue()</code> on the entry, if found,
 469:    * or null if no entry is found. Note that maps which permit null values
 470:    * may also return null if the key was removed.  If the entrySet does not
 471:    * support removal, this will also fail. This is O(n), so many
 472:    * implementations override it for efficiency.
 473:    *
 474:    * @param key the key to remove
 475:    * @return the value the key mapped to, or null if not present.
 476:    *         Null may also be returned if null values are allowed
 477:    *         in the map and the value of this mapping is null.
 478:    * @throws UnsupportedOperationException if deletion is unsupported
 479:    * @see Iterator#remove()
 480:    */
 481:   public V remove(Object key)
 482:   {
 483:     Iterator<Map.Entry<K, V>> entries = entrySet().iterator();
 484:     int pos = size();
 485:     while (--pos >= 0)
 486:       {
 487:         Map.Entry<K, V> entry = entries.next();
 488:         if (equals(key, entry.getKey()))
 489:           {
 490:             // Must get the value before we remove it from iterator.
 491:             V r = entry.getValue();
 492:             entries.remove();
 493:             return r;
 494:           }
 495:       }
 496:     return null;
 497:   }
 498: 
 499:   /**
 500:    * Returns the number of key-value mappings in the map. If there are more
 501:    * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
 502:    * implemented as <code>entrySet().size()</code>.
 503:    *
 504:    * @return the number of mappings
 505:    * @see Set#size()
 506:    */
 507:   public int size()
 508:   {
 509:     return entrySet().size();
 510:   }
 511: 
 512:   /**
 513:    * Returns a String representation of this map. This is a listing of the
 514:    * map entries (which are specified in Map.Entry as being
 515:    * <code>getKey() + "=" + getValue()</code>), separated by a comma and
 516:    * space (", "), and surrounded by braces ('{' and '}'). This implementation
 517:    * uses a StringBuffer and iterates over the entrySet to build the String.
 518:    * Note that this can fail with an exception if underlying keys or
 519:    * values complete abruptly in toString().
 520:    *
 521:    * @return a String representation
 522:    * @see Map.Entry#toString()
 523:    */
 524:   public String toString()
 525:   {
 526:     Iterator<Map.Entry<K, V>> entries = entrySet().iterator();
 527:     StringBuffer r = new StringBuffer("{");
 528:     for (int pos = size(); pos > 0; pos--)
 529:       {
 530:         Map.Entry<K, V> entry = entries.next();
 531:         r.append(entry.getKey());
 532:         r.append('=');
 533:         r.append(entry.getValue());
 534:         if (pos > 1)
 535:           r.append(", ");
 536:       }
 537:     r.append("}");
 538:     return r.toString();
 539:   }
 540: 
 541:   /**
 542:    * Returns a collection or bag view of this map's values. The collection
 543:    * is backed by the map, so changes in one show up in the other.
 544:    * Modifications while an iteration is in progress produce undefined
 545:    * behavior. The collection supports removal if entrySet() does, but
 546:    * does not support element addition.
 547:    * <p>
 548:    *
 549:    * This implementation creates an AbstractCollection, where the iterator
 550:    * wraps the entrySet iterator, size defers to the Map's size, and contains
 551:    * defers to the Map's containsValue. The collection is created on first
 552:    * use, and returned on subsequent uses, although since no synchronization
 553:    * occurs, there is a slight possibility of creating two collections.
 554:    *
 555:    * @return a Collection view of the values
 556:    * @see Collection#iterator()
 557:    * @see #size()
 558:    * @see #containsValue(Object)
 559:    * @see #keySet()
 560:    */
 561:   public Collection<V> values()
 562:   {
 563:     if (values == null)
 564:       values = new AbstractCollection<V>()
 565:       {
 566:      /**
 567:      * Returns the number of values stored in
 568:      * the backing map.
 569:      *
 570:      * @return The number of values.
 571:      */
 572:        public int size()
 573:         {
 574:           return AbstractMap.this.size();
 575:         }
 576: 
 577:     /**
 578:      * Returns true if the backing map contains
 579:      * the supplied value.
 580:      *
 581:      * @param value The value to search for.
 582:      * @return True if the value was found, false otherwise.
 583:      */
 584:         public boolean contains(Object value)
 585:         {
 586:           return containsValue(value);
 587:         }
 588: 
 589:     /**
 590:      * Returns an iterator which iterates over the
 591:      * values in the backing map, by using a wrapper
 592:      * around the iterator returned by <code>entrySet()</code>.
 593:      *
 594:      * @return An iterator over the values.
 595:      */
 596:         public Iterator<V> iterator()
 597:         {
 598:           return new Iterator<V>()
 599:           {
 600:         /**
 601:          * The iterator returned by <code>entrySet()</code>.
 602:          */
 603:             private final Iterator<Map.Entry<K, V>> map_iterator
 604:           = entrySet().iterator();
 605: 
 606:          /**
 607:           * Returns true if a call to <code>next()</call> will
 608:           * return another value.
 609:           *
 610:           * @return True if the iterator has not yet reached
 611:           * the last value.
 612:           */
 613:             public boolean hasNext()
 614:             {
 615:               return map_iterator.hasNext();
 616:             }
 617: 
 618:          /**
 619:           * Returns the value from the next entry retrieved
 620:           * by the underlying <code>entrySet()</code> iterator.
 621:           *
 622:           * @return The next value.
 623:           */
 624:             public V next()
 625:             {
 626:               return map_iterator.next().getValue();
 627:             }
 628: 
 629:          /**
 630:           * Removes the map entry which has a key equal
 631:           * to that returned by the last call to
 632:           * <code>next()</code>.
 633:           *
 634:           * @throws UnsupportedOperationException if the
 635:           *         map doesn't support removal.
 636:           */
 637:             public void remove()
 638:             {
 639:               map_iterator.remove();
 640:             }
 641:           };
 642:         }
 643:       };
 644:     return values;
 645:   }
 646: 
 647:   /**
 648:    * Compare two objects according to Collection semantics.
 649:    *
 650:    * @param o1 the first object
 651:    * @param o2 the second object
 652:    * @return o1 == o2 || (o1 != null && o1.equals(o2))
 653:    */
 654:   // Package visible for use throughout java.util.
 655:   // It may be inlined since it is final.
 656:   static final boolean equals(Object o1, Object o2)
 657:   {
 658:     return o1 == o2 || (o1 != null && o1.equals(o2));
 659:   }
 660: 
 661:   /**
 662:    * Hash an object according to Collection semantics.
 663:    *
 664:    * @param o the object to hash
 665:    * @return o1 == null ? 0 : o1.hashCode()
 666:    */
 667:   // Package visible for use throughout java.util.
 668:   // It may be inlined since it is final.
 669:   static final int hashCode(Object o)
 670:   {
 671:     return o == null ? 0 : o.hashCode();
 672:   }
 673: 
 674:   /**
 675:    * A class which implements Map.Entry. It is shared by HashMap, TreeMap,
 676:    * Hashtable, and Collections. It is not specified by the JDK, but makes
 677:    * life much easier.
 678:    *
 679:    * @author Jon Zeppieri
 680:    * @author Eric Blake (ebb9@email.byu.edu)
 681:    * 
 682:    * @since 1.6
 683:    */
 684:   public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable
 685:   {
 686: 
 687:     /**
 688:      * Compatible with JDK 1.6
 689:      */
 690:     private static final long serialVersionUID = -8499721149061103585L;
 691: 
 692:     /**
 693:      * The key. Package visible for direct manipulation.
 694:      */
 695:     K key;
 696: 
 697:     /**
 698:      * The value. Package visible for direct manipulation.
 699:      */
 700:     V value;
 701: 
 702:     /**
 703:      * Basic constructor initializes the fields.
 704:      * @param newKey the key
 705:      * @param newValue the value
 706:      */
 707:     public SimpleEntry(K newKey, V newValue)
 708:     {
 709:       key = newKey;
 710:       value = newValue;
 711:     }
 712:     
 713:     public SimpleEntry(Entry<? extends K, ? extends V> entry)
 714:     {
 715:       this(entry.getKey(), entry.getValue());
 716:     }
 717: 
 718:     /**
 719:      * Compares the specified object with this entry. Returns true only if
 720:      * the object is a mapping of identical key and value. In other words,
 721:      * this must be:<br>
 722:      * <pre>(o instanceof Map.Entry)
 723:      *       && (getKey() == null ? ((HashMap) o).getKey() == null
 724:      *           : getKey().equals(((HashMap) o).getKey()))
 725:      *       && (getValue() == null ? ((HashMap) o).getValue() == null
 726:      *           : getValue().equals(((HashMap) o).getValue()))</pre>
 727:      *
 728:      * @param o the object to compare
 729:      * @return <code>true</code> if it is equal
 730:      */
 731:     public boolean equals(Object o)
 732:     {
 733:       if (! (o instanceof Map.Entry))
 734:         return false;
 735:       // Optimize for our own entries.
 736:       if (o instanceof SimpleEntry)
 737:         {
 738:           SimpleEntry e = (SimpleEntry) o;
 739:           return (AbstractMap.equals(key, e.key)
 740:                   && AbstractMap.equals(value, e.value));
 741:         }
 742:       Map.Entry e = (Map.Entry) o;
 743:       return (AbstractMap.equals(key, e.getKey())
 744:               && AbstractMap.equals(value, e.getValue()));
 745:     }
 746: 
 747:     /**
 748:      * Get the key corresponding to this entry.
 749:      *
 750:      * @return the key
 751:      */
 752:     public K getKey()
 753:     {
 754:       return key;
 755:     }
 756: 
 757:     /**
 758:      * Get the value corresponding to this entry. If you already called
 759:      * Iterator.remove(), the behavior undefined, but in this case it works.
 760:      *
 761:      * @return the value
 762:      */
 763:     public V getValue()
 764:     {
 765:       return value;
 766:     }
 767: 
 768:     /**
 769:      * Returns the hash code of the entry.  This is defined as the exclusive-or
 770:      * of the hashcodes of the key and value (using 0 for null). In other
 771:      * words, this must be:<br>
 772:      * <pre>(getKey() == null ? 0 : getKey().hashCode())
 773:      *       ^ (getValue() == null ? 0 : getValue().hashCode())</pre>
 774:      *
 775:      * @return the hash code
 776:      */
 777:     public int hashCode()
 778:     {
 779:       return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value));
 780:     }
 781: 
 782:     /**
 783:      * Replaces the value with the specified object. This writes through
 784:      * to the map, unless you have already called Iterator.remove(). It
 785:      * may be overridden to restrict a null value.
 786:      *
 787:      * @param newVal the new value to store
 788:      * @return the old value
 789:      * @throws NullPointerException if the map forbids null values.
 790:      * @throws UnsupportedOperationException if the map doesn't support
 791:      *          <code>put()</code>.
 792:      * @throws ClassCastException if the value is of a type unsupported
 793:      *         by the map.
 794:      * @throws IllegalArgumentException if something else about this
 795:      *         value prevents it being stored in the map.
 796:      */
 797:     public V setValue(V newVal)
 798:     {
 799:       V r = value;
 800:       value = newVal;
 801:       return r;
 802:     }
 803: 
 804:     /**
 805:      * This provides a string representation of the entry. It is of the form
 806:      * "key=value", where string concatenation is used on key and value.
 807:      *
 808:      * @return the string representation
 809:      */
 810:     public String toString()
 811:     {
 812:       return key + "=" + value;
 813:     }
 814:   } // class SimpleEntry
 815:   
 816:   
 817: }