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