ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/AbstractMap.java
Revision: 1.25
Committed: Tue Sep 11 15:13:59 2007 UTC (16 years, 8 months ago) by jsr166
Branch: MAIN
Changes since 1.24: +17 -1 lines
Log Message:
6519662: (coll) AbstractMap collection views should override clear and isEmpty

File Contents

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