1   /*
2    * %W% %E%
3    *
4    * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5    * ORACLE 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   * interface, to minimize the effort required to implement this interface.
14   *
15   * <p>To implement an unmodifiable map, the programmer needs only to extend this
16   * 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   * should not support the <tt>remove</tt> method.
21   *
22   * <p>To implement a modifiable map, the programmer must additionally override
23   * 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   * <tt>remove</tt> method.
27   *
28   * <p>The programmer should generally provide a void (no argument) and map
29   * constructor, as per the recommendation in the <tt>Map</tt> interface
30   * specification.
31   *
32   * <p>The documentation for each non-abstract method in this class describes its
33   * implementation in detail.  Each of these methods may be overridden if the
34   * map being implemented admits a more efficient implementation.
35   *
36   * <p>This class is a member of the
37   * <a href="{@docRoot}/../technotes/guides/collections/index.html">
38   * Java Collections Framework</a>.
39   *
40   * @param <K> the type of keys maintained by this map
41   * @param <V> the type of mapped values
42   *
43   * @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       * {@inheritDoc}
63       *
64       * <p>This implementation returns <tt>entrySet().size()</tt>.
65       */
66      public int size() {
67      return entrySet().size();
68      }
69  
70      /**
71       * {@inheritDoc}
72       *
73       * <p>This implementation returns <tt>size() == 0</tt>.
74       */
75      public boolean isEmpty() {
76      return size() == 0;
77      }
78  
79      /**
80       * {@inheritDoc}
81       *
82       * <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       *
88       * @throws ClassCastException   {@inheritDoc}
89       * @throws NullPointerException {@inheritDoc}
90       */
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      * {@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      *
119      * @throws ClassCastException   {@inheritDoc}
120      * @throws NullPointerException {@inheritDoc}
121      */
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      * {@inheritDoc}
142      *
143      * <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      *
150      * @throws ClassCastException            {@inheritDoc}
151      * @throws NullPointerException          {@inheritDoc}
152      */
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      * {@inheritDoc}
176      *
177      * <p>This implementation always throws an
178      * <tt>UnsupportedOperationException</tt>.
179      *
180      * @throws UnsupportedOperationException {@inheritDoc}
181      * @throws ClassCastException            {@inheritDoc}
182      * @throws NullPointerException          {@inheritDoc}
183      * @throws IllegalArgumentException      {@inheritDoc}
184      */
185     public V put(K key, V value) {
186     throw new UnsupportedOperationException();
187     }
188 
189     /**
190      * {@inheritDoc}
191      *
192      * <p>This implementation iterates over <tt>entrySet()</tt> searching for an
193      * 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      * from the collection (and the backing map) with the iterator's
196      * <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      * 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      *
206      * @throws UnsupportedOperationException {@inheritDoc}
207      * @throws ClassCastException            {@inheritDoc}
208      * @throws NullPointerException          {@inheritDoc}
209      */
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      * {@inheritDoc}
240      *
241      * <p>This implementation iterates over the specified map's
242      * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
243      * operation once for each entry returned by the iteration.
244      *
245      * <p>Note that this implementation throws an
246      * <tt>UnsupportedOperationException</tt> if this map does not support
247      * the <tt>put</tt> operation and the specified map is nonempty.
248      *
249      * @throws UnsupportedOperationException {@inheritDoc}
250      * @throws ClassCastException            {@inheritDoc}
251      * @throws NullPointerException          {@inheritDoc}
252      * @throws IllegalArgumentException      {@inheritDoc}
253      */
254     public void putAll(Map<? extends K, ? extends V> m) {
255         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
256             put(e.getKey(), e.getValue());
257     }
258 
259     /**
260      * {@inheritDoc}
261      *
262      * <p>This implementation calls <tt>entrySet().clear()</tt>.
263      *
264      * <p>Note that this implementation throws an
265      * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
266      * does not support the <tt>clear</tt> operation.
267      *
268      * @throws UnsupportedOperationException {@inheritDoc}
269      */
270     public void clear() {
271     entrySet().clear();
272     }
273 
274 
275     // Views
276 
277     /**
278      * Each of these fields are initialized to contain an instance of the
279      * appropriate view the first time this view is requested.  The views are
280      * stateless, so there's no reason to create more than one of each.
281      */
282     transient volatile Set<K>        keySet = null;
283     transient volatile Collection<V> values = null;
284 
285     /**
286      * {@inheritDoc}
287      *
288      * <p>This implementation returns a set that subclasses {@link AbstractSet}.
289      * The subclass's iterator method returns a "wrapper object" over this
290      * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
291      * delegates to this map's <tt>size</tt> method and the
292      * <tt>contains</tt> method delegates to this map's
293      * <tt>containsKey</tt> method.
294      *
295      * <p>The set is created the first time this method is called,
296      * and returned in response to all subsequent calls.  No synchronization
297      * is performed, so there is a slight chance that multiple calls to this
298      * method will not all return the same set.
299      */
300     public Set<K> keySet() {
301     if (keySet == null) {
302         keySet = new AbstractSet<K>() {
303         public Iterator<K> iterator() {
304             return new Iterator<K>() {
305             private Iterator<Entry<K,V>> i = entrySet().iterator();
306 
307             public boolean hasNext() {
308                 return i.hasNext();
309             }
310 
311             public K next() {
312                 return i.next().getKey();
313             }
314 
315             public void remove() {
316                 i.remove();
317             }
318                     };
319         }
320 
321         public int size() {
322             return AbstractMap.this.size();
323         }
324 
325         public boolean contains(Object k) {
326             return AbstractMap.this.containsKey(k);
327         }
328         };
329     }
330     return keySet;
331     }
332 
333     /**
334      * {@inheritDoc}
335      *
336      * <p>This implementation returns a collection that subclasses {@link
337      * AbstractCollection}.  The subclass's iterator method returns a
338      * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
339      * The <tt>size</tt> method delegates to this map's <tt>size</tt>
340      * method and the <tt>contains</tt> method delegates to this map's
341      * <tt>containsValue</tt> method.
342      *
343      * <p>The collection is created the first time this method is called, and
344      * returned in response to all subsequent calls.  No synchronization is
345      * performed, so there is a slight chance that multiple calls to this
346      * method will not all return the same collection.
347      */
348     public Collection<V> values() {
349     if (values == null) {
350         values = new AbstractCollection<V>() {
351         public Iterator<V> iterator() {
352             return new Iterator<V>() {
353             private Iterator<Entry<K,V>> i = entrySet().iterator();
354 
355             public boolean hasNext() {
356                 return i.hasNext();
357             }
358 
359             public V next() {
360                 return i.next().getValue();
361             }
362 
363             public void remove() {
364                 i.remove();
365             }
366                     };
367                 }
368 
369         public int size() {
370             return AbstractMap.this.size();
371         }
372 
373         public boolean contains(Object v) {
374             return AbstractMap.this.containsValue(v);
375         }
376         };
377     }
378     return values;
379     }
380 
381     public abstract Set<Entry<K,V>> entrySet();
382 
383 
384     // Comparison and hashing
385 
386     /**
387      * Compares the specified object with this map for equality.  Returns
388      * <tt>true</tt> if the given object is also a map and the two maps
389      * represent the same mappings.  More formally, two maps <tt>m1</tt> and
390      * <tt>m2</tt> represent the same mappings if
391      * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
392      * <tt>equals</tt> method works properly across different implementations
393      * of the <tt>Map</tt> interface.
394      *
395      * <p>This implementation first checks if the specified object is this map;
396      * if so it returns <tt>true</tt>.  Then, it checks if the specified
397      * object is a map whose size is identical to the size of this map; if
398      * not, it returns <tt>false</tt>.  If so, it iterates over this map's
399      * <tt>entrySet</tt> collection, and checks that the specified map
400      * contains each mapping that this map contains.  If the specified map
401      * fails to contain such a mapping, <tt>false</tt> is returned.  If the
402      * iteration completes, <tt>true</tt> is returned.
403      *
404      * @param o object to be compared for equality with this map
405      * @return <tt>true</tt> if the specified object is equal to this map
406      */
407     public boolean equals(Object o) {
408     if (o == this)
409         return true;
410 
411     if (!(o instanceof Map))
412         return false;
413     Map<K,V> m = (Map<K,V>) o;
414     if (m.size() != size())
415         return false;
416 
417         try {
418             Iterator<Entry<K,V>> i = entrySet().iterator();
419             while (i.hasNext()) {
420                 Entry<K,V> e = i.next();
421         K key = e.getKey();
422                 V value = e.getValue();
423                 if (value == null) {
424                     if (!(m.get(key)==null && m.containsKey(key)))
425                         return false;
426                 } else {
427                     if (!value.equals(m.get(key)))
428                         return false;
429                 }
430             }
431         } catch (ClassCastException unused) {
432             return false;
433         } catch (NullPointerException unused) {
434             return false;
435         }
436 
437     return true;
438     }
439 
440     /**
441      * Returns the hash code value for this map.  The hash code of a map is
442      * defined to be the sum of the hash codes of each entry in the map's
443      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
444      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
445      * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
446      * {@link Object#hashCode}.
447      *
448      * <p>This implementation iterates over <tt>entrySet()</tt>, calling
449      * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
450      * set, and adding up the results.
451      *
452      * @return the hash code value for this map
453      * @see Map.Entry#hashCode()
454      * @see Object#equals(Object)
455      * @see Set#equals(Object)
456      */
457     public int hashCode() {
458     int h = 0;
459     Iterator<Entry<K,V>> i = entrySet().iterator();
460     while (i.hasNext())
461         h += i.next().hashCode();
462     return h;
463     }
464 
465     /**
466      * Returns a string representation of this map.  The string representation
467      * consists of a list of key-value mappings in the order returned by the
468      * map's <tt>entrySet</tt> view's iterator, enclosed in braces
469      * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
470      * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
471      * the key followed by an equals sign (<tt>"="</tt>) followed by the
472      * associated value.  Keys and values are converted to strings as by
473      * {@link String#valueOf(Object)}.
474      *
475      * @return a string representation of this map
476      */
477     public String toString() {
478     Iterator<Entry<K,V>> i = entrySet().iterator();
479     if (! i.hasNext())
480         return "{}";
481 
482     StringBuilder sb = new StringBuilder();
483     sb.append('{');
484     for (;;) {
485         Entry<K,V> e = i.next();
486         K key = e.getKey();
487         V value = e.getValue();
488         sb.append(key   == this ? "(this Map)" : key);
489         sb.append('=');
490         sb.append(value == this ? "(this Map)" : value);
491         if (! i.hasNext())
492         return sb.append('}').toString();
493         sb.append(", ");
494     }
495     }
496 
497     /**
498      * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
499      * and values themselves are not cloned.
500      *
501      * @return a shallow copy of this map
502      */
503     protected Object clone() throws CloneNotSupportedException {
504         AbstractMap<K,V> result = (AbstractMap<K,V>)super.clone();
505         result.keySet = null;
506         result.values = null;
507         return result;
508     }
509 
510     /**
511      * Utility method for SimpleEntry and SimpleImmutableEntry.
512      * Test for equality, checking for nulls.
513      */
514     private static boolean eq(Object o1, Object o2) {
515         return o1 == null ? o2 == null : o1.equals(o2);
516     }
517 
518     // Implementation Note: SimpleEntry and SimpleImmutableEntry
519     // are distinct unrelated classes, even though they share
520     // some code. Since you can't add or subtract final-ness
521     // of a field in a subclass, they can't share representations,
522     // and the amount of duplicated code is too small to warrant
523     // exposing a common abstract class.
524 
525 
526     /**
527      * An Entry maintaining a key and a value.  The value may be
528      * changed using the <tt>setValue</tt> method.  This class
529      * facilitates the process of building custom map
530      * implementations. For example, it may be convenient to return
531      * arrays of <tt>SimpleEntry</tt> instances in method
532      * <tt>Map.entrySet().toArray</tt>.
533      *
534      * @since 1.6
535      */
536     public static class SimpleEntry<K,V>
537     implements Entry<K,V>, java.io.Serializable
538     {
539     private static final long serialVersionUID = -8499721149061103585L;
540 
541     private final K key;
542     private V value;
543 
544         /**
545          * Creates an entry representing a mapping from the specified
546          * key to the specified value.
547          *
548          * @param key the key represented by this entry
549          * @param value the value represented by this entry
550          */
551     public SimpleEntry(K key, V value) {
552         this.key   = key;
553             this.value = value;
554     }
555 
556         /**
557          * Creates an entry representing the same mapping as the
558          * specified entry.
559          *
560          * @param entry the entry to copy
561          */
562     public SimpleEntry(Entry<? extends K, ? extends V> entry) {
563         this.key   = entry.getKey();
564             this.value = entry.getValue();
565     }
566 
567         /**
568      * Returns the key corresponding to this entry.
569      *
570      * @return the key corresponding to this entry
571      */
572     public K getKey() {
573         return key;
574     }
575 
576         /**
577      * Returns the value corresponding to this entry.
578      *
579      * @return the value corresponding to this entry
580      */
581     public V getValue() {
582         return value;
583     }
584 
585         /**
586      * Replaces the value corresponding to this entry with the specified
587      * value.
588      *
589      * @param value new value to be stored in this entry
590      * @return the old value corresponding to the entry
591          */
592     public V setValue(V value) {
593         V oldValue = this.value;
594         this.value = value;
595         return oldValue;
596     }
597 
598     /**
599      * Compares the specified object with this entry for equality.
600      * Returns {@code true} if the given object is also a map entry and
601      * the two entries represent the same mapping.  More formally, two
602      * entries {@code e1} and {@code e2} represent the same mapping
603      * if<pre>
604      *   (e1.getKey()==null ?
605      *    e2.getKey()==null :
606      *    e1.getKey().equals(e2.getKey()))
607      *   &amp;&amp;
608      *   (e1.getValue()==null ?
609      *    e2.getValue()==null :
610      *    e1.getValue().equals(e2.getValue()))</pre>
611      * This ensures that the {@code equals} method works properly across
612      * different implementations of the {@code Map.Entry} interface.
613      *
614      * @param o object to be compared for equality with this map entry
615      * @return {@code true} if the specified object is equal to this map
616      *     entry
617      * @see    #hashCode
618      */
619     public boolean equals(Object o) {
620         if (!(o instanceof Map.Entry))
621         return false;
622         Map.Entry e = (Map.Entry)o;
623         return eq(key, e.getKey()) && eq(value, e.getValue());
624     }
625 
626     /**
627      * Returns the hash code value for this map entry.  The hash code
628      * of a map entry {@code e} is defined to be: <pre>
629      *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
630      *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
631      * This ensures that {@code e1.equals(e2)} implies that
632      * {@code e1.hashCode()==e2.hashCode()} for any two Entries
633      * {@code e1} and {@code e2}, as required by the general
634      * contract of {@link Object#hashCode}.
635      *
636      * @return the hash code value for this map entry
637      * @see    #equals
638      */
639     public int hashCode() {
640         return (key   == null ? 0 :   key.hashCode()) ^
641            (value == null ? 0 : value.hashCode());
642     }
643 
644         /**
645          * Returns a String representation of this map entry.  This
646          * implementation returns the string representation of this
647          * entry's key followed by the equals character ("<tt>=</tt>")
648          * followed by the string representation of this entry's value.
649          *
650          * @return a String representation of this map entry
651          */
652     public String toString() {
653         return key + "=" + value;
654     }
655 
656     }
657 
658     /**
659      * An Entry maintaining an immutable key and value.  This class
660      * does not support method <tt>setValue</tt>.  This class may be
661      * convenient in methods that return thread-safe snapshots of
662      * key-value mappings.
663      *
664      * @since 1.6
665      */
666     public static class SimpleImmutableEntry<K,V>
667     implements Entry<K,V>, java.io.Serializable
668     {
669     private static final long serialVersionUID = 7138329143949025153L;
670 
671     private final K key;
672     private final V value;
673 
674         /**
675          * Creates an entry representing a mapping from the specified
676          * key to the specified value.
677          *
678          * @param key the key represented by this entry
679          * @param value the value represented by this entry
680          */
681     public SimpleImmutableEntry(K key, V value) {
682         this.key   = key;
683             this.value = value;
684     }
685 
686         /**
687          * Creates an entry representing the same mapping as the
688          * specified entry.
689          *
690          * @param entry the entry to copy
691          */
692     public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
693         this.key   = entry.getKey();
694             this.value = entry.getValue();
695     }
696 
697         /**
698      * Returns the key corresponding to this entry.
699      *
700      * @return the key corresponding to this entry
701      */
702     public K getKey() {
703         return key;
704     }
705 
706         /**
707      * Returns the value corresponding to this entry.
708      *
709      * @return the value corresponding to this entry
710      */
711     public V getValue() {
712         return value;
713     }
714 
715         /**
716      * Replaces the value corresponding to this entry with the specified
717      * value (optional operation).  This implementation simply throws
718          * <tt>UnsupportedOperationException</tt>, as this class implements
719          * an <i>immutable</i> map entry.
720      *
721      * @param value new value to be stored in this entry
722      * @return (Does not return)
723      * @throws UnsupportedOperationException always
724          */
725     public V setValue(V value) {
726             throw new UnsupportedOperationException();
727         }
728 
729     /**
730      * Compares the specified object with this entry for equality.
731      * Returns {@code true} if the given object is also a map entry and
732      * the two entries represent the same mapping.  More formally, two
733      * entries {@code e1} and {@code e2} represent the same mapping
734      * if<pre>
735      *   (e1.getKey()==null ?
736      *    e2.getKey()==null :
737      *    e1.getKey().equals(e2.getKey()))
738      *   &amp;&amp;
739      *   (e1.getValue()==null ?
740      *    e2.getValue()==null :
741      *    e1.getValue().equals(e2.getValue()))</pre>
742      * This ensures that the {@code equals} method works properly across
743      * different implementations of the {@code Map.Entry} interface.
744      *
745      * @param o object to be compared for equality with this map entry
746      * @return {@code true} if the specified object is equal to this map
747      *     entry
748      * @see    #hashCode
749      */
750     public boolean equals(Object o) {
751         if (!(o instanceof Map.Entry))
752         return false;
753         Map.Entry e = (Map.Entry)o;
754         return eq(key, e.getKey()) && eq(value, e.getValue());
755     }
756 
757     /**
758      * Returns the hash code value for this map entry.  The hash code
759      * of a map entry {@code e} is defined to be: <pre>
760      *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
761      *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
762      * This ensures that {@code e1.equals(e2)} implies that
763      * {@code e1.hashCode()==e2.hashCode()} for any two Entries
764      * {@code e1} and {@code e2}, as required by the general
765      * contract of {@link Object#hashCode}.
766      *
767      * @return the hash code value for this map entry
768      * @see    #equals
769      */
770     public int hashCode() {
771         return (key   == null ? 0 :   key.hashCode()) ^
772            (value == null ? 0 : value.hashCode());
773     }
774 
775         /**
776          * Returns a String representation of this map entry.  This
777          * implementation returns the string representation of this
778          * entry's key followed by the equals character ("<tt>=</tt>")
779          * followed by the string representation of this entry's value.
780          *
781          * @return a String representation of this map entry
782          */
783     public String toString() {
784         return key + "=" + value;
785     }
786 
787     }
788 
789 }
790