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 <tt>Map</tt> 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 <tt>entrySet</tt> method, which 35 * returns a set-view of the map's mappings. Typically, the returned set 36 * will, in turn, be implemented atop <tt>AbstractSet</tt>. This set should 37 * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator 38 * should not support the <tt>remove</tt> method. 39 * 40 * <p>To implement a modifiable map, the programmer must additionally override 41 * this class's <tt>put</tt> method (which otherwise throws an 42 * <tt>UnsupportedOperationException</tt>), and the iterator returned by 43 * <tt>entrySet().iterator()</tt> must additionally implement its 44 * <tt>remove</tt> method. 45 * 46 * <p>The programmer should generally provide a void (no argument) and map 47 * constructor, as per the recommendation in the <tt>Map</tt> 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 */ AbstractMap()73 protected AbstractMap() { 74 } 75 76 // Query Operations 77 78 /** 79 * {@inheritDoc} 80 * 81 * @implSpec 82 * This implementation returns <tt>entrySet().size()</tt>. 83 */ size()84 public int size() { 85 return entrySet().size(); 86 } 87 88 /** 89 * {@inheritDoc} 90 * 91 * @implSpec 92 * This implementation returns <tt>size() == 0</tt>. 93 */ isEmpty()94 public boolean isEmpty() { 95 return size() == 0; 96 } 97 98 /** 99 * {@inheritDoc} 100 * 101 * @implSpec 102 * This implementation iterates over <tt>entrySet()</tt> searching 103 * for an entry with the specified value. If such an entry is found, 104 * <tt>true</tt> is returned. If the iteration terminates without 105 * finding such an entry, <tt>false</tt> 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 <tt>entrySet()</tt> searching 134 * for an entry with the specified key. If such an entry is found, 135 * <tt>true</tt> is returned. If the iteration terminates without 136 * finding such an entry, <tt>false</tt> 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 <tt>entrySet()</tt> 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, <tt>null</tt> 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 * <tt>UnsupportedOperationException</tt>. 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 <tt>entrySet()</tt> searching for an 217 * entry with the specified key. If such an entry is found, its value is 218 * obtained with its <tt>getValue</tt> operation, the entry is removed 219 * from the collection (and the backing map) with the iterator's 220 * <tt>remove</tt> operation, and the saved value is returned. If the 221 * iteration terminates without finding such an entry, <tt>null</tt> 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 * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt> 227 * iterator does not support the <tt>remove</tt> 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 * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt> 268 * operation once for each entry returned by the iteration. 269 * 270 * <p>Note that this implementation throws an 271 * <tt>UnsupportedOperationException</tt> if this map does not support 272 * the <tt>put</tt> 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 <tt>entrySet().clear()</tt>. 289 * 290 * <p>Note that this implementation throws an 291 * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt> 292 * does not support the <tt>clear</tt> 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 <tt>entrySet()</tt> iterator. The <tt>size</tt> method 337 * delegates to this map's <tt>size</tt> method and the 338 * <tt>contains</tt> method delegates to this map's 339 * <tt>containsKey</tt> 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 <tt>entrySet()</tt> iterator. 396 * The <tt>size</tt> method delegates to this map's <tt>size</tt> 397 * method and the <tt>contains</tt> method delegates to this map's 398 * <tt>containsValue</tt> 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 * <tt>true</tt> if the given object is also a map and the two maps 456 * represent the same mappings. More formally, two maps <tt>m1</tt> and 457 * <tt>m2</tt> represent the same mappings if 458 * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This ensures that the 459 * <tt>equals</tt> method works properly across different implementations 460 * of the <tt>Map</tt> interface. 461 * 462 * @implSpec 463 * This implementation first checks if the specified object is this map; 464 * if so it returns <tt>true</tt>. 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 <tt>false</tt>. If so, it iterates over this map's 467 * <tt>entrySet</tt> 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, <tt>false</tt> is returned. If the 470 * iteration completes, <tt>true</tt> is returned. 471 * 472 * @param o object to be compared for equality with this map 473 * @return <tt>true</tt> 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 Iterator<Entry<K,V>> i = entrySet().iterator(); 487 while (i.hasNext()) { 488 Entry<K,V> e = i.next(); 489 K key = e.getKey(); 490 V value = e.getValue(); 491 if (value == null) { 492 if (!(m.get(key)==null && m.containsKey(key))) 493 return false; 494 } else { 495 if (!value.equals(m.get(key))) 496 return false; 497 } 498 } 499 } catch (ClassCastException unused) { 500 return false; 501 } catch (NullPointerException unused) { 502 return false; 503 } 504 505 return true; 506 } 507 508 /** 509 * Returns the hash code value for this map. The hash code of a map is 510 * defined to be the sum of the hash codes of each entry in the map's 511 * <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt> 512 * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps 513 * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of 514 * {@link Object#hashCode}. 515 * 516 * @implSpec 517 * This implementation iterates over <tt>entrySet()</tt>, calling 518 * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the 519 * set, and adding up the results. 520 * 521 * @return the hash code value for this map 522 * @see Map.Entry#hashCode() 523 * @see Object#equals(Object) 524 * @see Set#equals(Object) 525 */ hashCode()526 public int hashCode() { 527 int h = 0; 528 Iterator<Entry<K,V>> i = entrySet().iterator(); 529 while (i.hasNext()) 530 h += i.next().hashCode(); 531 return h; 532 } 533 534 /** 535 * Returns a string representation of this map. The string representation 536 * consists of a list of key-value mappings in the order returned by the 537 * map's <tt>entrySet</tt> view's iterator, enclosed in braces 538 * (<tt>"{}"</tt>). Adjacent mappings are separated by the characters 539 * <tt>", "</tt> (comma and space). Each key-value mapping is rendered as 540 * the key followed by an equals sign (<tt>"="</tt>) followed by the 541 * associated value. Keys and values are converted to strings as by 542 * {@link String#valueOf(Object)}. 543 * 544 * @return a string representation of this map 545 */ toString()546 public String toString() { 547 Iterator<Entry<K,V>> i = entrySet().iterator(); 548 if (! i.hasNext()) 549 return "{}"; 550 551 StringBuilder sb = new StringBuilder(); 552 sb.append('{'); 553 for (;;) { 554 Entry<K,V> e = i.next(); 555 K key = e.getKey(); 556 V value = e.getValue(); 557 sb.append(key == this ? "(this Map)" : key); 558 sb.append('='); 559 sb.append(value == this ? "(this Map)" : value); 560 if (! i.hasNext()) 561 return sb.append('}').toString(); 562 sb.append(',').append(' '); 563 } 564 } 565 566 /** 567 * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys 568 * and values themselves are not cloned. 569 * 570 * @return a shallow copy of this map 571 */ clone()572 protected Object clone() throws CloneNotSupportedException { 573 AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone(); 574 result.keySet = null; 575 result.values = null; 576 return result; 577 } 578 579 /** 580 * Utility method for SimpleEntry and SimpleImmutableEntry. 581 * Test for equality, checking for nulls. 582 * 583 * NB: Do not replace with Object.equals until JDK-8015417 is resolved. 584 */ eq(Object o1, Object o2)585 private static boolean eq(Object o1, Object o2) { 586 return o1 == null ? o2 == null : o1.equals(o2); 587 } 588 589 // Implementation Note: SimpleEntry and SimpleImmutableEntry 590 // are distinct unrelated classes, even though they share 591 // some code. Since you can't add or subtract final-ness 592 // of a field in a subclass, they can't share representations, 593 // and the amount of duplicated code is too small to warrant 594 // exposing a common abstract class. 595 596 597 /** 598 * An Entry maintaining a key and a value. The value may be 599 * changed using the <tt>setValue</tt> method. This class 600 * facilitates the process of building custom map 601 * implementations. For example, it may be convenient to return 602 * arrays of <tt>SimpleEntry</tt> instances in method 603 * <tt>Map.entrySet().toArray</tt>. 604 * 605 * @since 1.6 606 */ 607 public static class SimpleEntry<K,V> 608 implements Entry<K,V>, java.io.Serializable 609 { 610 private static final long serialVersionUID = -8499721149061103585L; 611 612 private final K key; 613 private V value; 614 615 /** 616 * Creates an entry representing a mapping from the specified 617 * key to the specified value. 618 * 619 * @param key the key represented by this entry 620 * @param value the value represented by this entry 621 */ SimpleEntry(K key, V value)622 public SimpleEntry(K key, V value) { 623 this.key = key; 624 this.value = value; 625 } 626 627 /** 628 * Creates an entry representing the same mapping as the 629 * specified entry. 630 * 631 * @param entry the entry to copy 632 */ SimpleEntry(Entry<? extends K, ? extends V> entry)633 public SimpleEntry(Entry<? extends K, ? extends V> entry) { 634 this.key = entry.getKey(); 635 this.value = entry.getValue(); 636 } 637 638 /** 639 * Returns the key corresponding to this entry. 640 * 641 * @return the key corresponding to this entry 642 */ getKey()643 public K getKey() { 644 return key; 645 } 646 647 /** 648 * Returns the value corresponding to this entry. 649 * 650 * @return the value corresponding to this entry 651 */ getValue()652 public V getValue() { 653 return value; 654 } 655 656 /** 657 * Replaces the value corresponding to this entry with the specified 658 * value. 659 * 660 * @param value new value to be stored in this entry 661 * @return the old value corresponding to the entry 662 */ setValue(V value)663 public V setValue(V value) { 664 V oldValue = this.value; 665 this.value = value; 666 return oldValue; 667 } 668 669 /** 670 * Compares the specified object with this entry for equality. 671 * Returns {@code true} if the given object is also a map entry and 672 * the two entries represent the same mapping. More formally, two 673 * entries {@code e1} and {@code e2} represent the same mapping 674 * if<pre> 675 * (e1.getKey()==null ? 676 * e2.getKey()==null : 677 * e1.getKey().equals(e2.getKey())) 678 * && 679 * (e1.getValue()==null ? 680 * e2.getValue()==null : 681 * e1.getValue().equals(e2.getValue()))</pre> 682 * This ensures that the {@code equals} method works properly across 683 * different implementations of the {@code Map.Entry} interface. 684 * 685 * @param o object to be compared for equality with this map entry 686 * @return {@code true} if the specified object is equal to this map 687 * entry 688 * @see #hashCode 689 */ equals(Object o)690 public boolean equals(Object o) { 691 if (!(o instanceof Map.Entry)) 692 return false; 693 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 694 return eq(key, e.getKey()) && eq(value, e.getValue()); 695 } 696 697 /** 698 * Returns the hash code value for this map entry. The hash code 699 * of a map entry {@code e} is defined to be: <pre> 700 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 701 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 702 * This ensures that {@code e1.equals(e2)} implies that 703 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 704 * {@code e1} and {@code e2}, as required by the general 705 * contract of {@link Object#hashCode}. 706 * 707 * @return the hash code value for this map entry 708 * @see #equals 709 */ hashCode()710 public int hashCode() { 711 return (key == null ? 0 : key.hashCode()) ^ 712 (value == null ? 0 : value.hashCode()); 713 } 714 715 /** 716 * Returns a String representation of this map entry. This 717 * implementation returns the string representation of this 718 * entry's key followed by the equals character ("<tt>=</tt>") 719 * followed by the string representation of this entry's value. 720 * 721 * @return a String representation of this map entry 722 */ toString()723 public String toString() { 724 return key + "=" + value; 725 } 726 727 } 728 729 /** 730 * An Entry maintaining an immutable key and value. This class 731 * does not support method <tt>setValue</tt>. This class may be 732 * convenient in methods that return thread-safe snapshots of 733 * key-value mappings. 734 * 735 * @since 1.6 736 */ 737 public static class SimpleImmutableEntry<K,V> 738 implements Entry<K,V>, java.io.Serializable 739 { 740 private static final long serialVersionUID = 7138329143949025153L; 741 742 private final K key; 743 private final V value; 744 745 /** 746 * Creates an entry representing a mapping from the specified 747 * key to the specified value. 748 * 749 * @param key the key represented by this entry 750 * @param value the value represented by this entry 751 */ SimpleImmutableEntry(K key, V value)752 public SimpleImmutableEntry(K key, V value) { 753 this.key = key; 754 this.value = value; 755 } 756 757 /** 758 * Creates an entry representing the same mapping as the 759 * specified entry. 760 * 761 * @param entry the entry to copy 762 */ SimpleImmutableEntry(Entry<? extends K, ? extends V> entry)763 public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) { 764 this.key = entry.getKey(); 765 this.value = entry.getValue(); 766 } 767 768 /** 769 * Returns the key corresponding to this entry. 770 * 771 * @return the key corresponding to this entry 772 */ getKey()773 public K getKey() { 774 return key; 775 } 776 777 /** 778 * Returns the value corresponding to this entry. 779 * 780 * @return the value corresponding to this entry 781 */ getValue()782 public V getValue() { 783 return value; 784 } 785 786 /** 787 * Replaces the value corresponding to this entry with the specified 788 * value (optional operation). This implementation simply throws 789 * <tt>UnsupportedOperationException</tt>, as this class implements 790 * an <i>immutable</i> map entry. 791 * 792 * @param value new value to be stored in this entry 793 * @return (Does not return) 794 * @throws UnsupportedOperationException always 795 */ setValue(V value)796 public V setValue(V value) { 797 throw new UnsupportedOperationException(); 798 } 799 800 /** 801 * Compares the specified object with this entry for equality. 802 * Returns {@code true} if the given object is also a map entry and 803 * the two entries represent the same mapping. More formally, two 804 * entries {@code e1} and {@code e2} represent the same mapping 805 * if<pre> 806 * (e1.getKey()==null ? 807 * e2.getKey()==null : 808 * e1.getKey().equals(e2.getKey())) 809 * && 810 * (e1.getValue()==null ? 811 * e2.getValue()==null : 812 * e1.getValue().equals(e2.getValue()))</pre> 813 * This ensures that the {@code equals} method works properly across 814 * different implementations of the {@code Map.Entry} interface. 815 * 816 * @param o object to be compared for equality with this map entry 817 * @return {@code true} if the specified object is equal to this map 818 * entry 819 * @see #hashCode 820 */ equals(Object o)821 public boolean equals(Object o) { 822 if (!(o instanceof Map.Entry)) 823 return false; 824 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 825 return eq(key, e.getKey()) && eq(value, e.getValue()); 826 } 827 828 /** 829 * Returns the hash code value for this map entry. The hash code 830 * of a map entry {@code e} is defined to be: <pre> 831 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ 832 * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> 833 * This ensures that {@code e1.equals(e2)} implies that 834 * {@code e1.hashCode()==e2.hashCode()} for any two Entries 835 * {@code e1} and {@code e2}, as required by the general 836 * contract of {@link Object#hashCode}. 837 * 838 * @return the hash code value for this map entry 839 * @see #equals 840 */ hashCode()841 public int hashCode() { 842 return (key == null ? 0 : key.hashCode()) ^ 843 (value == null ? 0 : value.hashCode()); 844 } 845 846 /** 847 * Returns a String representation of this map entry. This 848 * implementation returns the string representation of this 849 * entry's key followed by the equals character ("<tt>=</tt>") 850 * followed by the string representation of this entry's value. 851 * 852 * @return a String representation of this map entry 853 */ toString()854 public String toString() { 855 return key + "=" + value; 856 } 857 858 } 859 860 } 861