ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/AbstractMap.java
Revision: 1.12
Committed: Fri Jun 10 16:06:46 2005 UTC (18 years, 11 months ago) by jsr166
Branch: MAIN
Changes since 1.11: +10 -10 lines
Log Message:
StringBuffer->StringBuilder

File Contents

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