ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/AbstractMap.java
Revision: 1.24
Committed: Sun May 20 07:54:01 2007 UTC (17 years ago) by jsr166
Branch: MAIN
Changes since 1.23: +21 -3 lines
Log Message:
License update

File Contents

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