1 /* 2 * Copyright (c) 1997, 2018, 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}/java.base/java/util/package-summary.html#CollectionsFramework"> 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 */ AbstractMap()73 protected AbstractMap() { 74 } 75 76 // Query Operations 77 78 /** 79 * {@inheritDoc} 80 * 81 * @implSpec 82 * This implementation returns {@code entrySet().size()}. 83 */ size()84 public int size() { 85 return entrySet().size(); 86 } 87 88 /** 89 * {@inheritDoc} 90 * 91 * @implSpec 92 * This implementation returns {@code size() == 0}. 93 */ isEmpty()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 */ containsValue(Object value)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 */ containsKey(Object key)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 */ get(Object key)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 */ put(K key, V value)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 */ remove(Object key)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 */ putAll(Map<? extends K, ? extends V> m)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 */ clear()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 * <p>Since there is no synchronization performed while accessing these fields, 309 * it is expected that java.util.Map view classes using these fields have 310 * no non-final fields (or any fields at all except for outer-this). Adhering 311 * to this rule would make the races on these fields benign. 312 * 313 * <p>It is also imperative that implementations read the field only once, 314 * as in: 315 * 316 * <pre> {@code 317 * public Set<K> keySet() { 318 * Set<K> ks = keySet; // single racy read 319 * if (ks == null) { 320 * ks = new KeySet(); 321 * keySet = ks; 322 * } 323 * return ks; 324 * } 325 *}</pre> 326 */ 327 transient Set<K> keySet; 328 transient Collection<V> values; 329 330 /** 331 * {@inheritDoc} 332 * 333 * @implSpec 334 * This implementation returns a set that subclasses {@link AbstractSet}. 335 * The subclass's iterator method returns a "wrapper object" over this 336 * map's {@code entrySet()} iterator. The {@code size} method 337 * delegates to this map's {@code size} method and the 338 * {@code contains} method delegates to this map's 339 * {@code containsKey} method. 340 * 341 * <p>The set is created the first time this method is called, 342 * and returned in response to all subsequent calls. No synchronization 343 * is performed, so there is a slight chance that multiple calls to this 344 * method will not all return the same set. 345 */ keySet()346 public Set<K> keySet() { 347 Set<K> ks = keySet; 348 if (ks == null) { 349 ks = new AbstractSet<K>() { 350 public Iterator<K> iterator() { 351 return new Iterator<K>() { 352 private Iterator<Entry<K,V>> i = entrySet().iterator(); 353 354 public boolean hasNext() { 355 return i.hasNext(); 356 } 357 358 public K next() { 359 return i.next().getKey(); 360 } 361 362 public void remove() { 363 i.remove(); 364 } 365 }; 366 } 367 368 public int size() { 369 return AbstractMap.this.size(); 370 } 371 372 public boolean isEmpty() { 373 return AbstractMap.this.isEmpty(); 374 } 375 376 public void clear() { 377 AbstractMap.this.clear(); 378 } 379 380 public boolean contains(Object k) { 381 return AbstractMap.this.containsKey(k); 382 } 383 }; 384 keySet = ks; 385 } 386 return ks; 387 } 388 389 /** 390 * {@inheritDoc} 391 * 392 * @implSpec 393 * This implementation returns a collection that subclasses {@link 394 * AbstractCollection}. The subclass's iterator method returns a 395 * "wrapper object" over this map's {@code entrySet()} iterator. 396 * The {@code size} method delegates to this map's {@code size} 397 * method and the {@code contains} method delegates to this map's 398 * {@code containsValue} method. 399 * 400 * <p>The collection is created the first time this method is called, and 401 * returned in response to all subsequent calls. No synchronization is 402 * performed, so there is a slight chance that multiple calls to this 403 * method will not all return the same collection. 404 */ values()405 public Collection<V> values() { 406 Collection<V> vals = values; 407 if (vals == null) { 408 vals = new AbstractCollection<V>() { 409 public Iterator<V> iterator() { 410 return new Iterator<V>() { 411 private Iterator<Entry<K,V>> i = entrySet().iterator(); 412 413 public boolean hasNext() { 414 return i.hasNext(); 415 } 416 417 public V next() { 418 return i.next().getValue(); 419 } 420 421 public void remove() { 422 i.remove(); 423 } 424 }; 425 } 426 427 public int size() { 428 return AbstractMap.this.size(); 429 } 430 431 public boolean isEmpty() { 432 return AbstractMap.this.isEmpty(); 433 } 434 435 public void clear() { 436 AbstractMap.this.clear(); 437 } 438 439 public boolean contains(Object v) { 440 return AbstractMap.this.containsValue(v); 441 } 442 }; 443 values = vals; 444 } 445 return vals; 446 } 447 entrySet()448 public abstract Set<Entry<K,V>> entrySet(); 449 450 451 // Comparison and hashing 452 453 /** 454 * Compares the specified object with this map for equality. Returns 455 * {@code true} if the given object is also a map and the two maps 456 * represent the same mappings. More formally, two maps {@code m1} and 457 * {@code m2} represent the same mappings if 458 * {@code m1.entrySet().equals(m2.entrySet())}. This ensures that the 459 * {@code equals} method works properly across different implementations 460 * of the {@code Map} interface. 461 * 462 * @implSpec 463 * This implementation first checks if the specified object is this map; 464 * if so it returns {@code true}. Then, it checks if the specified 465 * object is a map whose size is identical to the size of this map; if 466 * not, it returns {@code false}. If so, it iterates over this map's 467 * {@code entrySet} collection, and checks that the specified map 468 * contains each mapping that this map contains. If the specified map 469 * fails to contain such a mapping, {@code false} is returned. If the 470 * iteration completes, {@code true} is returned. 471 * 472 * @param o object to be compared for equality with this map 473 * @return {@code true} if the specified object is equal to this map 474 */ equals(Object o)475 public boolean equals(Object o) { 476 if (o == this) 477 return true; 478 479 if (!(o instanceof Map)) 480 return false; 481 Map<?,?> m = (Map<?,?>) o; 482 if (m.size() != size()) 483 return false; 484 485 try { 486 for (Entry<K, V> e : entrySet()) { 487 K key = e.getKey(); 488 V value = e.getValue(); 489 if (value == null) { 490 if (!(m.get(key) == null && m.containsKey(key))) 491 return false; 492 } else { 493 if (!value.equals(m.get(key))) 494 return false; 495 } 496 } 497 } catch (ClassCastException unused) { 498 return false; 499 } catch (NullPointerException unused) { 500 return false; 501 } 502 503 return true; 504 } 505 506 /** 507 * Returns the hash code value for this map. The hash code of a map is 508 * defined to be the sum of the hash codes of each entry in the map's 509 * {@code entrySet()} view. This ensures that {@code m1.equals(m2)} 510 * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps 511 * {@code m1} and {@code m2}, as required by the general contract of 512 * {@link Object#hashCode}. 513 * 514 * @implSpec 515 * This implementation iterates over {@code entrySet()}, calling 516 * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the 517 * set, and adding up the results. 518 * 519 * @return the hash code value for this map 520 * @see Map.Entry#hashCode() 521 * @see Object#equals(Object) 522 * @see Set#equals(Object) 523 */ hashCode()524 public int hashCode() { 525 int h = 0; 526 for (Entry<K, V> entry : entrySet()) 527 h += entry.hashCode(); 528 return h; 529 } 530 531 /** 532 * Returns a string representation of this map. The string representation 533 * consists of a list of key-value mappings in the order returned by the 534 * map's {@code entrySet} view's iterator, enclosed in braces 535 * ({@code "{}"}). Adjacent mappings are separated by the characters 536 * {@code ", "} (comma and space). Each key-value mapping is rendered as 537 * the key followed by an equals sign ({@code "="}) followed by the 538 * associated value. Keys and values are converted to strings as by 539 * {@link String#valueOf(Object)}. 540 * 541 * @return a string representation of this map 542 */ toString()543 public String toString() { 544 Iterator<Entry<K,V>> i = entrySet().iterator(); 545 if (! i.hasNext()) 546 return "{}"; 547 548 StringBuilder sb = new StringBuilder(); 549 sb.append('{'); 550 for (;;) { 551 Entry<K,V> e = i.next(); 552 K key = e.getKey(); 553 V value = e.getValue(); 554 sb.append(key == this ? "(this Map)" : key); 555 sb.append('='); 556 sb.append(value == this ? "(this Map)" : value); 557 if (! i.hasNext()) 558 return sb.append('}').toString(); 559 sb.append(',').append(' '); 560 } 561 } 562 563 /** 564 * Returns a shallow copy of this {@code AbstractMap} instance: the keys 565 * and values themselves are not cloned. 566 * 567 * @return a shallow copy of this map 568 */ clone()569 protected Object clone() throws CloneNotSupportedException { 570 AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone(); 571 result.keySet = null; 572 result.values = null; 573 return result; 574 } 575 576 /** 577 * Utility method for SimpleEntry and SimpleImmutableEntry. 578 * Test for equality, checking for nulls. 579 * 580 * NB: Do not replace with Object.equals until JDK-8015417 is resolved. 581 */ eq(Object o1, Object o2)582 private static boolean eq(Object o1, Object o2) { 583 return o1 == null ? o2 == null : o1.equals(o2); 584 } 585 586 // Implementation Note: SimpleEntry and SimpleImmutableEntry 587 // are distinct unrelated classes, even though they share 588 // some code. Since you can't add or subtract final-ness 589 // of a field in a subclass, they can't share representations, 590 // and the amount of duplicated code is too small to warrant 591 // exposing a common abstract class. 592 593 594 /** 595 * An Entry maintaining a key and a value. The value may be 596 * changed using the {@code setValue} method. This class 597 * facilitates the process of building custom map 598 * implementations. For example, it may be convenient to return 599 * arrays of {@code SimpleEntry} instances in method 600 * {@code Map.entrySet().toArray}. 601 * 602 * @since 1.6 603 */ 604 public static class SimpleEntry<K,V> 605 implements Entry<K,V>, java.io.Serializable 606 { 607 private static final long serialVersionUID = -8499721149061103585L; 608 609 private final K key; 610 private V value; 611 612 /** 613 * Creates an entry representing a mapping from the specified 614 * key to the specified value. 615 * 616 * @param key the key represented by this entry 617 * @param value the value represented by this entry 618 */ SimpleEntry(K key, V value)619 public SimpleEntry(K key, V value) { 620 this.key = key; 621 this.value = value; 622 } 623 624 /** 625 * Creates an entry representing the same mapping as the 626 * specified entry. 627 * 628 * @param entry the entry to copy 629 */ SimpleEntry(Entry<? extends K, ? extends V> entry)630 public SimpleEntry(Entry<? extends K, ? extends V> entry) { 631 this.key = entry.getKey(); 632 this.value = entry.getValue(); 633 } 634 635 /** 636 * Returns the key corresponding to this entry. 637 * 638 * @return the key corresponding to this entry 639 */ getKey()640 public K getKey() { 641 return key; 642 } 643 644 /** 645 * Returns the value corresponding to this entry. 646 * 647 * @return the value corresponding to this entry 648 */ getValue()649 public V getValue() { 650 return value; 651 } 652 653 /** 654 * Replaces the value corresponding to this entry with the specified 655 * value. 656 * 657 * @param value new value to be stored in this entry 658 * @return the old value corresponding to the entry 659 */ setValue(V value)660 public V setValue(V value) { 661 V oldValue = this.value; 662 this.value = value; 663 return oldValue; 664 } 665 666 /** 667 * Compares the specified object with this entry for equality. 668 * Returns {@code true} if the given object is also a map entry and 669 * the two entries represent the same mapping. More formally, two 670 * entries {@code e1} and {@code e2} represent the same mapping 671 * if<pre> 672 * (e1.getKey()==null ? 673 * e2.getKey()==null : 674 * e1.getKey().equals(e2.getKey())) 675 * && 676 * (e1.getValue()==null ? 677 * e2.getValue()==null : 678 * e1.getValue().equals(e2.getValue()))</pre> 679 * This ensures that the {@code equals} method works properly across 680 * different implementations of the {@code Map.Entry} interface. 681 * 682 * @param o object to be compared for equality with this map entry 683 * @return {@code true} if the specified object is equal to this map 684 * entry 685 * @see #hashCode 686 */ equals(Object o)687 public boolean equals(Object o) { 688 if (!(o instanceof Map.Entry)) 689 return false; 690 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 691 return eq(key, e.getKey()) && eq(value, e.getValue()); 692 } 693 694 /** 695 * Returns the hash code value for this map entry. The hash code 696 * of a map entry {@code e} is defined to be: <pre> 697 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 698 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 699 * This ensures that {@code e1.equals(e2)} implies that 700 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 701 * {@code e1} and {@code e2}, as required by the general 702 * contract of {@link Object#hashCode}. 703 * 704 * @return the hash code value for this map entry 705 * @see #equals 706 */ hashCode()707 public int hashCode() { 708 return (key == null ? 0 : key.hashCode()) ^ 709 (value == null ? 0 : value.hashCode()); 710 } 711 712 /** 713 * Returns a String representation of this map entry. This 714 * implementation returns the string representation of this 715 * entry's key followed by the equals character ("{@code =}") 716 * followed by the string representation of this entry's value. 717 * 718 * @return a String representation of this map entry 719 */ toString()720 public String toString() { 721 return key + "=" + value; 722 } 723 724 } 725 726 /** 727 * An Entry maintaining an immutable key and value. This class 728 * does not support method {@code setValue}. This class may be 729 * convenient in methods that return thread-safe snapshots of 730 * key-value mappings. 731 * 732 * @since 1.6 733 */ 734 public static class SimpleImmutableEntry<K,V> 735 implements Entry<K,V>, java.io.Serializable 736 { 737 private static final long serialVersionUID = 7138329143949025153L; 738 739 private final K key; 740 private final V value; 741 742 /** 743 * Creates an entry representing a mapping from the specified 744 * key to the specified value. 745 * 746 * @param key the key represented by this entry 747 * @param value the value represented by this entry 748 */ SimpleImmutableEntry(K key, V value)749 public SimpleImmutableEntry(K key, V value) { 750 this.key = key; 751 this.value = value; 752 } 753 754 /** 755 * Creates an entry representing the same mapping as the 756 * specified entry. 757 * 758 * @param entry the entry to copy 759 */ SimpleImmutableEntry(Entry<? extends K, ? extends V> entry)760 public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) { 761 this.key = entry.getKey(); 762 this.value = entry.getValue(); 763 } 764 765 /** 766 * Returns the key corresponding to this entry. 767 * 768 * @return the key corresponding to this entry 769 */ getKey()770 public K getKey() { 771 return key; 772 } 773 774 /** 775 * Returns the value corresponding to this entry. 776 * 777 * @return the value corresponding to this entry 778 */ getValue()779 public V getValue() { 780 return value; 781 } 782 783 /** 784 * Replaces the value corresponding to this entry with the specified 785 * value (optional operation). This implementation simply throws 786 * {@code UnsupportedOperationException}, as this class implements 787 * an <i>immutable</i> map entry. 788 * 789 * @param value new value to be stored in this entry 790 * @return (Does not return) 791 * @throws UnsupportedOperationException always 792 */ setValue(V value)793 public V setValue(V value) { 794 throw new UnsupportedOperationException(); 795 } 796 797 /** 798 * Compares the specified object with this entry for equality. 799 * Returns {@code true} if the given object is also a map entry and 800 * the two entries represent the same mapping. More formally, two 801 * entries {@code e1} and {@code e2} represent the same mapping 802 * if<pre> 803 * (e1.getKey()==null ? 804 * e2.getKey()==null : 805 * e1.getKey().equals(e2.getKey())) 806 * && 807 * (e1.getValue()==null ? 808 * e2.getValue()==null : 809 * e1.getValue().equals(e2.getValue()))</pre> 810 * This ensures that the {@code equals} method works properly across 811 * different implementations of the {@code Map.Entry} interface. 812 * 813 * @param o object to be compared for equality with this map entry 814 * @return {@code true} if the specified object is equal to this map 815 * entry 816 * @see #hashCode 817 */ equals(Object o)818 public boolean equals(Object o) { 819 if (!(o instanceof Map.Entry)) 820 return false; 821 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 822 return eq(key, e.getKey()) && eq(value, e.getValue()); 823 } 824 825 /** 826 * Returns the hash code value for this map entry. The hash code 827 * of a map entry {@code e} is defined to be: <pre> 828 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 829 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 830 * This ensures that {@code e1.equals(e2)} implies that 831 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 832 * {@code e1} and {@code e2}, as required by the general 833 * contract of {@link Object#hashCode}. 834 * 835 * @return the hash code value for this map entry 836 * @see #equals 837 */ hashCode()838 public int hashCode() { 839 return (key == null ? 0 : key.hashCode()) ^ 840 (value == null ? 0 : value.hashCode()); 841 } 842 843 /** 844 * Returns a String representation of this map entry. This 845 * implementation returns the string representation of this 846 * entry's key followed by the equals character ("{@code =}") 847 * followed by the string representation of this entry's value. 848 * 849 * @return a String representation of this map entry 850 */ toString()851 public String toString() { 852 return key + "=" + value; 853 } 854 855 } 856 857 } 858