1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 import java.util.Map.Entry; 28 29 /** 30 * This class provides a skeletal implementation of the {@code Map} 31 * interface, to minimize the effort required to implement this interface. 32 * 33 * <p>To implement an unmodifiable map, the programmer needs only to extend this 34 * class and provide an implementation for the {@code entrySet} method, which 35 * returns a set-view of the map's mappings. Typically, the returned set 36 * will, in turn, be implemented atop {@code AbstractSet}. This set should 37 * not support the {@code add} or {@code remove} methods, and its iterator 38 * should not support the {@code remove} method. 39 * 40 * <p>To implement a modifiable map, the programmer must additionally override 41 * this class's {@code put} method (which otherwise throws an 42 * {@code UnsupportedOperationException}), and the iterator returned by 43 * {@code entrySet().iterator()} must additionally implement its 44 * {@code remove} method. 45 * 46 * <p>The programmer should generally provide a void (no argument) and map 47 * constructor, as per the recommendation in the {@code Map} interface 48 * specification. 49 * 50 * <p>The documentation for each non-abstract method in this class describes its 51 * implementation in detail. Each of these methods may be overridden if the 52 * map being implemented admits a more efficient implementation. 53 * 54 * <p>This class is a member of the 55 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 56 * Java Collections Framework</a>. 57 * 58 * @param <K> the type of keys maintained by this map 59 * @param <V> the type of mapped values 60 * 61 * @author Josh Bloch 62 * @author Neal Gafter 63 * @see Map 64 * @see Collection 65 * @since 1.2 66 */ 67 68 public abstract class AbstractMap<K,V> implements Map<K,V> { 69 /** 70 * Sole constructor. (For invocation by subclass constructors, typically 71 * implicit.) 72 */ 73 protected AbstractMap() { 74 } 75 76 // Query Operations 77 78 /** 79 * {@inheritDoc} 80 * 81 * @implSpec 82 * This implementation returns {@code entrySet().size()}. 83 */ 84 public int size() { 85 return entrySet().size(); 86 } 87 88 /** 89 * {@inheritDoc} 90 * 91 * @implSpec 92 * This implementation returns {@code size() == 0}. 93 */ 94 public boolean isEmpty() { 95 return size() == 0; 96 } 97 98 /** 99 * {@inheritDoc} 100 * 101 * @implSpec 102 * This implementation iterates over {@code entrySet()} searching 103 * for an entry with the specified value. If such an entry is found, 104 * {@code true} is returned. If the iteration terminates without 105 * finding such an entry, {@code false} is returned. Note that this 106 * implementation requires linear time in the size of the map. 107 * 108 * @throws ClassCastException {@inheritDoc} 109 * @throws NullPointerException {@inheritDoc} 110 */ 111 public boolean containsValue(Object value) { 112 Iterator<Entry<K,V>> i = entrySet().iterator(); 113 if (value==null) { 114 while (i.hasNext()) { 115 Entry<K,V> e = i.next(); 116 if (e.getValue()==null) 117 return true; 118 } 119 } else { 120 while (i.hasNext()) { 121 Entry<K,V> e = i.next(); 122 if (value.equals(e.getValue())) 123 return true; 124 } 125 } 126 return false; 127 } 128 129 /** 130 * {@inheritDoc} 131 * 132 * @implSpec 133 * This implementation iterates over {@code entrySet()} searching 134 * for an entry with the specified key. If such an entry is found, 135 * {@code true} is returned. If the iteration terminates without 136 * finding such an entry, {@code false} is returned. Note that this 137 * implementation requires linear time in the size of the map; many 138 * implementations will override this method. 139 * 140 * @throws ClassCastException {@inheritDoc} 141 * @throws NullPointerException {@inheritDoc} 142 */ 143 public boolean containsKey(Object key) { 144 Iterator<Map.Entry<K,V>> i = entrySet().iterator(); 145 if (key==null) { 146 while (i.hasNext()) { 147 Entry<K,V> e = i.next(); 148 if (e.getKey()==null) 149 return true; 150 } 151 } else { 152 while (i.hasNext()) { 153 Entry<K,V> e = i.next(); 154 if (key.equals(e.getKey())) 155 return true; 156 } 157 } 158 return false; 159 } 160 161 /** 162 * {@inheritDoc} 163 * 164 * @implSpec 165 * This implementation iterates over {@code entrySet()} searching 166 * for an entry with the specified key. If such an entry is found, 167 * the entry's value is returned. If the iteration terminates without 168 * finding such an entry, {@code null} is returned. Note that this 169 * implementation requires linear time in the size of the map; many 170 * implementations will override this method. 171 * 172 * @throws ClassCastException {@inheritDoc} 173 * @throws NullPointerException {@inheritDoc} 174 */ 175 public V get(Object key) { 176 Iterator<Entry<K,V>> i = entrySet().iterator(); 177 if (key==null) { 178 while (i.hasNext()) { 179 Entry<K,V> e = i.next(); 180 if (e.getKey()==null) 181 return e.getValue(); 182 } 183 } else { 184 while (i.hasNext()) { 185 Entry<K,V> e = i.next(); 186 if (key.equals(e.getKey())) 187 return e.getValue(); 188 } 189 } 190 return null; 191 } 192 193 194 // Modification Operations 195 196 /** 197 * {@inheritDoc} 198 * 199 * @implSpec 200 * This implementation always throws an 201 * {@code UnsupportedOperationException}. 202 * 203 * @throws UnsupportedOperationException {@inheritDoc} 204 * @throws ClassCastException {@inheritDoc} 205 * @throws NullPointerException {@inheritDoc} 206 * @throws IllegalArgumentException {@inheritDoc} 207 */ 208 public V put(K key, V value) { 209 throw new UnsupportedOperationException(); 210 } 211 212 /** 213 * {@inheritDoc} 214 * 215 * @implSpec 216 * This implementation iterates over {@code entrySet()} searching for an 217 * entry with the specified key. If such an entry is found, its value is 218 * obtained with its {@code getValue} operation, the entry is removed 219 * from the collection (and the backing map) with the iterator's 220 * {@code remove} operation, and the saved value is returned. If the 221 * iteration terminates without finding such an entry, {@code null} is 222 * returned. Note that this implementation requires linear time in the 223 * size of the map; many implementations will override this method. 224 * 225 * <p>Note that this implementation throws an 226 * {@code UnsupportedOperationException} if the {@code entrySet} 227 * iterator does not support the {@code remove} method and this map 228 * contains a mapping for the specified key. 229 * 230 * @throws UnsupportedOperationException {@inheritDoc} 231 * @throws ClassCastException {@inheritDoc} 232 * @throws NullPointerException {@inheritDoc} 233 */ 234 public V remove(Object key) { 235 Iterator<Entry<K,V>> i = entrySet().iterator(); 236 Entry<K,V> correctEntry = null; 237 if (key==null) { 238 while (correctEntry==null && i.hasNext()) { 239 Entry<K,V> e = i.next(); 240 if (e.getKey()==null) 241 correctEntry = e; 242 } 243 } else { 244 while (correctEntry==null && i.hasNext()) { 245 Entry<K,V> e = i.next(); 246 if (key.equals(e.getKey())) 247 correctEntry = e; 248 } 249 } 250 251 V oldValue = null; 252 if (correctEntry !=null) { 253 oldValue = correctEntry.getValue(); 254 i.remove(); 255 } 256 return oldValue; 257 } 258 259 260 // Bulk Operations 261 262 /** 263 * {@inheritDoc} 264 * 265 * @implSpec 266 * This implementation iterates over the specified map's 267 * {@code entrySet()} collection, and calls this map's {@code put} 268 * operation once for each entry returned by the iteration. 269 * 270 * <p>Note that this implementation throws an 271 * {@code UnsupportedOperationException} if this map does not support 272 * the {@code put} operation and the specified map is nonempty. 273 * 274 * @throws UnsupportedOperationException {@inheritDoc} 275 * @throws ClassCastException {@inheritDoc} 276 * @throws NullPointerException {@inheritDoc} 277 * @throws IllegalArgumentException {@inheritDoc} 278 */ 279 public void putAll(Map<? extends K, ? extends V> m) { 280 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) 281 put(e.getKey(), e.getValue()); 282 } 283 284 /** 285 * {@inheritDoc} 286 * 287 * @implSpec 288 * This implementation calls {@code entrySet().clear()}. 289 * 290 * <p>Note that this implementation throws an 291 * {@code UnsupportedOperationException} if the {@code entrySet} 292 * does not support the {@code clear} operation. 293 * 294 * @throws UnsupportedOperationException {@inheritDoc} 295 */ 296 public void clear() { 297 entrySet().clear(); 298 } 299 300 301 // Views 302 303 /** 304 * Each of these fields are initialized to contain an instance of the 305 * appropriate view the first time this view is requested. The views are 306 * stateless, so there's no reason to create more than one of each. 307 */ 308 transient volatile Set<K> keySet; 309 transient volatile Collection<V> values; 310 311 /** 312 * {@inheritDoc} 313 * 314 * @implSpec 315 * This implementation returns a set that subclasses {@link AbstractSet}. 316 * The subclass's iterator method returns a "wrapper object" over this 317 * map's {@code entrySet()} iterator. The {@code size} method 318 * delegates to this map's {@code size} method and the 319 * {@code contains} method delegates to this map's 320 * {@code containsKey} method. 321 * 322 * <p>The set is created the first time this method is called, 323 * and returned in response to all subsequent calls. No synchronization 324 * is performed, so there is a slight chance that multiple calls to this 325 * method will not all return the same set. 326 */ 327 public Set<K> keySet() { 328 if (keySet == null) { 329 keySet = new AbstractSet<K>() { 330 public Iterator<K> iterator() { 331 return new Iterator<K>() { 332 private Iterator<Entry<K,V>> i = entrySet().iterator(); 333 334 public boolean hasNext() { 335 return i.hasNext(); 336 } 337 338 public K next() { 339 return i.next().getKey(); 340 } 341 342 public void remove() { 343 i.remove(); 344 } 345 }; 346 } 347 348 public int size() { 349 return AbstractMap.this.size(); 350 } 351 352 public boolean isEmpty() { 353 return AbstractMap.this.isEmpty(); 354 } 355 356 public void clear() { 357 AbstractMap.this.clear(); 358 } 359 360 public boolean contains(Object k) { 361 return AbstractMap.this.containsKey(k); 362 } 363 }; 364 } 365 return keySet; 366 } 367 368 /** 369 * {@inheritDoc} 370 * 371 * @implSpec 372 * This implementation returns a collection that subclasses {@link 373 * AbstractCollection}. The subclass's iterator method returns a 374 * "wrapper object" over this map's {@code entrySet()} iterator. 375 * The {@code size} method delegates to this map's {@code size} 376 * method and the {@code contains} method delegates to this map's 377 * {@code containsValue} method. 378 * 379 * <p>The collection is created the first time this method is called, and 380 * returned in response to all subsequent calls. No synchronization is 381 * performed, so there is a slight chance that multiple calls to this 382 * method will not all return the same collection. 383 */ 384 public Collection<V> values() { 385 if (values == null) { 386 values = new AbstractCollection<V>() { 387 public Iterator<V> iterator() { 388 return new Iterator<V>() { 389 private Iterator<Entry<K,V>> i = entrySet().iterator(); 390 391 public boolean hasNext() { 392 return i.hasNext(); 393 } 394 395 public V next() { 396 return i.next().getValue(); 397 } 398 399 public void remove() { 400 i.remove(); 401 } 402 }; 403 } 404 405 public int size() { 406 return AbstractMap.this.size(); 407 } 408 409 public boolean isEmpty() { 410 return AbstractMap.this.isEmpty(); 411 } 412 413 public void clear() { 414 AbstractMap.this.clear(); 415 } 416 417 public boolean contains(Object v) { 418 return AbstractMap.this.containsValue(v); 419 } 420 }; 421 } 422 return values; 423 } 424 425 public abstract Set<Entry<K,V>> entrySet(); 426 427 428 // Comparison and hashing 429 430 /** 431 * Compares the specified object with this map for equality. Returns 432 * {@code true} if the given object is also a map and the two maps 433 * represent the same mappings. More formally, two maps {@code m1} and 434 * {@code m2} represent the same mappings if 435 * {@code m1.entrySet().equals(m2.entrySet())}. This ensures that the 436 * {@code equals} method works properly across different implementations 437 * of the {@code Map} interface. 438 * 439 * @implSpec 440 * This implementation first checks if the specified object is this map; 441 * if so it returns {@code true}. Then, it checks if the specified 442 * object is a map whose size is identical to the size of this map; if 443 * not, it returns {@code false}. If so, it iterates over this map's 444 * {@code entrySet} collection, and checks that the specified map 445 * contains each mapping that this map contains. If the specified map 446 * fails to contain such a mapping, {@code false} is returned. If the 447 * iteration completes, {@code true} is returned. 448 * 449 * @param o object to be compared for equality with this map 450 * @return {@code true} if the specified object is equal to this map 451 */ 452 public boolean equals(Object o) { 453 if (o == this) 454 return true; 455 456 if (!(o instanceof Map)) 457 return false; 458 Map<?,?> m = (Map<?,?>) o; 459 if (m.size() != size()) 460 return false; 461 462 try { 463 for (Entry<K, V> e : entrySet()) { 464 K key = e.getKey(); 465 V value = e.getValue(); 466 if (value == null) { 467 if (!(m.get(key) == null && m.containsKey(key))) 468 return false; 469 } else { 470 if (!value.equals(m.get(key))) 471 return false; 472 } 473 } 474 } catch (ClassCastException unused) { 475 return false; 476 } catch (NullPointerException unused) { 477 return false; 478 } 479 480 return true; 481 } 482 483 /** 484 * Returns the hash code value for this map. The hash code of a map is 485 * defined to be the sum of the hash codes of each entry in the map's 486 * {@code entrySet()} view. This ensures that {@code m1.equals(m2)} 487 * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps 488 * {@code m1} and {@code m2}, as required by the general contract of 489 * {@link Object#hashCode}. 490 * 491 * @implSpec 492 * This implementation iterates over {@code entrySet()}, calling 493 * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the 494 * set, and adding up the results. 495 * 496 * @return the hash code value for this map 497 * @see Map.Entry#hashCode() 498 * @see Object#equals(Object) 499 * @see Set#equals(Object) 500 */ 501 public int hashCode() { 502 int h = 0; 503 for (Entry<K, V> entry : entrySet()) 504 h += entry.hashCode(); 505 return h; 506 } 507 508 /** 509 * Returns a string representation of this map. The string representation 510 * consists of a list of key-value mappings in the order returned by the 511 * map's {@code entrySet} view's iterator, enclosed in braces 512 * ({@code "{}"}). Adjacent mappings are separated by the characters 513 * {@code ", "} (comma and space). Each key-value mapping is rendered as 514 * the key followed by an equals sign ({@code "="}) followed by the 515 * associated value. Keys and values are converted to strings as by 516 * {@link String#valueOf(Object)}. 517 * 518 * @return a string representation of this map 519 */ 520 public String toString() { 521 Iterator<Entry<K,V>> i = entrySet().iterator(); 522 if (! i.hasNext()) 523 return "{}"; 524 525 StringBuilder sb = new StringBuilder(); 526 sb.append('{'); 527 for (;;) { 528 Entry<K,V> e = i.next(); 529 K key = e.getKey(); 530 V value = e.getValue(); 531 sb.append(key == this ? "(this Map)" : key); 532 sb.append('='); 533 sb.append(value == this ? "(this Map)" : value); 534 if (! i.hasNext()) 535 return sb.append('}').toString(); 536 sb.append(',').append(' '); 537 } 538 } 539 540 /** 541 * Returns a shallow copy of this {@code AbstractMap} instance: the keys 542 * and values themselves are not cloned. 543 * 544 * @return a shallow copy of this map 545 */ 546 protected Object clone() throws CloneNotSupportedException { 547 AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone(); 548 result.keySet = null; 549 result.values = null; 550 return result; 551 } 552 553 /** 554 * Utility method for SimpleEntry and SimpleImmutableEntry. 555 * Test for equality, checking for nulls. 556 * 557 * NB: Do not replace with Object.equals until JDK-8015417 is resolved. 558 */ 559 private static boolean eq(Object o1, Object o2) { 560 return o1 == null ? o2 == null : o1.equals(o2); 561 } 562 563 // Implementation Note: SimpleEntry and SimpleImmutableEntry 564 // are distinct unrelated classes, even though they share 565 // some code. Since you can't add or subtract final-ness 566 // of a field in a subclass, they can't share representations, 567 // and the amount of duplicated code is too small to warrant 568 // exposing a common abstract class. 569 570 571 /** 572 * An Entry maintaining a key and a value. The value may be 573 * changed using the {@code setValue} method. This class 574 * facilitates the process of building custom map 575 * implementations. For example, it may be convenient to return 576 * arrays of {@code SimpleEntry} instances in method 577 * {@code Map.entrySet().toArray}. 578 * 579 * @since 1.6 580 */ 581 public static class SimpleEntry<K,V> 582 implements Entry<K,V>, java.io.Serializable 583 { 584 private static final long serialVersionUID = -8499721149061103585L; 585 586 private final K key; 587 private V value; 588 589 /** 590 * Creates an entry representing a mapping from the specified 591 * key to the specified value. 592 * 593 * @param key the key represented by this entry 594 * @param value the value represented by this entry 595 */ 596 public SimpleEntry(K key, V value) { 597 this.key = key; 598 this.value = value; 599 } 600 601 /** 602 * Creates an entry representing the same mapping as the 603 * specified entry. 604 * 605 * @param entry the entry to copy 606 */ 607 public SimpleEntry(Entry<? extends K, ? extends V> entry) { 608 this.key = entry.getKey(); 609 this.value = entry.getValue(); 610 } 611 612 /** 613 * Returns the key corresponding to this entry. 614 * 615 * @return the key corresponding to this entry 616 */ 617 public K getKey() { 618 return key; 619 } 620 621 /** 622 * Returns the value corresponding to this entry. 623 * 624 * @return the value corresponding to this entry 625 */ 626 public V getValue() { 627 return value; 628 } 629 630 /** 631 * Replaces the value corresponding to this entry with the specified 632 * value. 633 * 634 * @param value new value to be stored in this entry 635 * @return the old value corresponding to the entry 636 */ 637 public V setValue(V value) { 638 V oldValue = this.value; 639 this.value = value; 640 return oldValue; 641 } 642 643 /** 644 * Compares the specified object with this entry for equality. 645 * Returns {@code true} if the given object is also a map entry and 646 * the two entries represent the same mapping. More formally, two 647 * entries {@code e1} and {@code e2} represent the same mapping 648 * if<pre> 649 * (e1.getKey()==null ? 650 * e2.getKey()==null : 651 * e1.getKey().equals(e2.getKey())) 652 * && 653 * (e1.getValue()==null ? 654 * e2.getValue()==null : 655 * e1.getValue().equals(e2.getValue()))</pre> 656 * This ensures that the {@code equals} method works properly across 657 * different implementations of the {@code Map.Entry} interface. 658 * 659 * @param o object to be compared for equality with this map entry 660 * @return {@code true} if the specified object is equal to this map 661 * entry 662 * @see #hashCode 663 */ 664 public boolean equals(Object o) { 665 if (!(o instanceof Map.Entry)) 666 return false; 667 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 668 return eq(key, e.getKey()) && eq(value, e.getValue()); 669 } 670 671 /** 672 * Returns the hash code value for this map entry. The hash code 673 * of a map entry {@code e} is defined to be: <pre> 674 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 675 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 676 * This ensures that {@code e1.equals(e2)} implies that 677 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 678 * {@code e1} and {@code e2}, as required by the general 679 * contract of {@link Object#hashCode}. 680 * 681 * @return the hash code value for this map entry 682 * @see #equals 683 */ 684 public int hashCode() { 685 return (key == null ? 0 : key.hashCode()) ^ 686 (value == null ? 0 : value.hashCode()); 687 } 688 689 /** 690 * Returns a String representation of this map entry. This 691 * implementation returns the string representation of this 692 * entry's key followed by the equals character ("{@code =}") 693 * followed by the string representation of this entry's value. 694 * 695 * @return a String representation of this map entry 696 */ 697 public String toString() { 698 return key + "=" + value; 699 } 700 701 } 702 703 /** 704 * An Entry maintaining an immutable key and value. This class 705 * does not support method {@code setValue}. This class may be 706 * convenient in methods that return thread-safe snapshots of 707 * key-value mappings. 708 * 709 * @since 1.6 710 */ 711 public static class SimpleImmutableEntry<K,V> 712 implements Entry<K,V>, java.io.Serializable 713 { 714 private static final long serialVersionUID = 7138329143949025153L; 715 716 private final K key; 717 private final V value; 718 719 /** 720 * Creates an entry representing a mapping from the specified 721 * key to the specified value. 722 * 723 * @param key the key represented by this entry 724 * @param value the value represented by this entry 725 */ 726 public SimpleImmutableEntry(K key, V value) { 727 this.key = key; 728 this.value = value; 729 } 730 731 /** 732 * Creates an entry representing the same mapping as the 733 * specified entry. 734 * 735 * @param entry the entry to copy 736 */ 737 public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) { 738 this.key = entry.getKey(); 739 this.value = entry.getValue(); 740 } 741 742 /** 743 * Returns the key corresponding to this entry. 744 * 745 * @return the key corresponding to this entry 746 */ 747 public K getKey() { 748 return key; 749 } 750 751 /** 752 * Returns the value corresponding to this entry. 753 * 754 * @return the value corresponding to this entry 755 */ 756 public V getValue() { 757 return value; 758 } 759 760 /** 761 * Replaces the value corresponding to this entry with the specified 762 * value (optional operation). This implementation simply throws 763 * {@code UnsupportedOperationException}, as this class implements 764 * an <i>immutable</i> map entry. 765 * 766 * @param value new value to be stored in this entry 767 * @return (Does not return) 768 * @throws UnsupportedOperationException always 769 */ 770 public V setValue(V value) { 771 throw new UnsupportedOperationException(); 772 } 773 774 /** 775 * Compares the specified object with this entry for equality. 776 * Returns {@code true} if the given object is also a map entry and 777 * the two entries represent the same mapping. More formally, two 778 * entries {@code e1} and {@code e2} represent the same mapping 779 * if<pre> 780 * (e1.getKey()==null ? 781 * e2.getKey()==null : 782 * e1.getKey().equals(e2.getKey())) 783 * && 784 * (e1.getValue()==null ? 785 * e2.getValue()==null : 786 * e1.getValue().equals(e2.getValue()))</pre> 787 * This ensures that the {@code equals} method works properly across 788 * different implementations of the {@code Map.Entry} interface. 789 * 790 * @param o object to be compared for equality with this map entry 791 * @return {@code true} if the specified object is equal to this map 792 * entry 793 * @see #hashCode 794 */ 795 public boolean equals(Object o) { 796 if (!(o instanceof Map.Entry)) 797 return false; 798 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 799 return eq(key, e.getKey()) && eq(value, e.getValue()); 800 } 801 802 /** 803 * Returns the hash code value for this map entry. The hash code 804 * of a map entry {@code e} is defined to be: <pre> 805 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 806 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 807 * This ensures that {@code e1.equals(e2)} implies that 808 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 809 * {@code e1} and {@code e2}, as required by the general 810 * contract of {@link Object#hashCode}. 811 * 812 * @return the hash code value for this map entry 813 * @see #equals 814 */ 815 public int hashCode() { 816 return (key == null ? 0 : key.hashCode()) ^ 817 (value == null ? 0 : value.hashCode()); 818 } 819 820 /** 821 * Returns a String representation of this map entry. This 822 * implementation returns the string representation of this 823 * entry's key followed by the equals character ("{@code =}") 824 * followed by the string representation of this entry's value. 825 * 826 * @return a String representation of this map entry 827 */ 828 public String toString() { 829 return key + "=" + value; 830 } 831 832 } 833 834 }