Java——AbstractMap

AbstractMap

实现Java顶级接口Map的一个抽象类。

1 类注释大意

该抽象类是实现接口Map的一个骨架,目的是为了后续实现Map的时候少费精力。

如果是实现成一个不可更改的Map,只需要继承这个抽象类和实现entrySet方法(AbstractMap中的一个抽象方法);如果要实现一个可以更改的Map,至少要实现put、remove和entrySet().iterator()(Set接口中的一个方法)方法。

 1 /**
 2  * This class provides a skeletal implementation of the <tt>Map</tt>
 3  * interface, to minimize the effort required to implement this interface.
 4  *
 5  * <p>To implement an unmodifiable map, the programmer needs only to extend this
 6  * class and provide an implementation for the <tt>entrySet</tt> method, which
 7  * returns a set-view of the map's mappings.  Typically, the returned set
 8  * will, in turn, be implemented atop <tt>AbstractSet</tt>.  This set should
 9  * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator
10  * should not support the <tt>remove</tt> method.
11  *
12  * <p>To implement a modifiable map, the programmer must additionally override
13  * this class's <tt>put</tt> method (which otherwise throws an
14  * <tt>UnsupportedOperationException</tt>), and the iterator returned by
15  * <tt>entrySet().iterator()</tt> must additionally implement its
16  * <tt>remove</tt> method.
17  *
18  * <p>The programmer should generally provide a void (no argument) and map
19  * constructor, as per the recommendation in the <tt>Map</tt> interface
20  * specification.
21  *
22  * <p>The documentation for each non-abstract method in this class describes its
23  * implementation in detail.  Each of these methods may be overridden if the
24  * map being implemented admits a more efficient implementation.
25  *
26  * <p>This class is a member of the
27  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
28  * Java Collections Framework</a>.
29  *
30  * @param <K> the type of keys maintained by this map
31  * @param <V> the type of mapped values
32  *
33  * @author  Josh Bloch
34  * @author  Neal Gafter
35  * @see Map
36  * @see Collection
37  * @since 1.2
38  */
View Code

2 源码

1 public abstract class AbstractMap<K,V> implements Map<K,V> {

该类只是单纯的实现Map接口。

2.1 查询操作(Query Operations)

  1 /**
  2      * {@inheritDoc}
  3      *
  4      * @implSpec
  5      * This implementation returns <tt>entrySet().size()</tt>.
  6      */
  7     public int size() {
  8         return entrySet().size();
  9     }
 10 
 11     /**
 12      * {@inheritDoc}
 13      *
 14      * @implSpec
 15      * This implementation returns <tt>size() == 0</tt>.
 16      */
 17     public boolean isEmpty() {
 18         return size() == 0;
 19     }
 20 
 21     /**
 22      * {@inheritDoc}
 23      *
 24      * @implSpec
 25      * This implementation iterates over <tt>entrySet()</tt> searching
 26      * for an entry with the specified value.  If such an entry is found,
 27      * <tt>true</tt> is returned.  If the iteration terminates without
 28      * finding such an entry, <tt>false</tt> is returned.  Note that this
 29      * implementation requires linear time in the size of the map.
 30      *
 31      * @throws ClassCastException   {@inheritDoc}
 32      * @throws NullPointerException {@inheritDoc}
 33      */
 34     public boolean containsValue(Object value) {
 35         Iterator<Entry<K,V>> i = entrySet().iterator();
 36         if (value==null) {
 37             while (i.hasNext()) {
 38                 Entry<K,V> e = i.next();
 39                 if (e.getValue()==null)
 40                     return true;
 41             }
 42         } else {
 43             while (i.hasNext()) {
 44                 Entry<K,V> e = i.next();
 45                 if (value.equals(e.getValue()))
 46                     return true;
 47             }
 48         }
 49         return false;
 50     }
 51 
 52     /**
 53      * {@inheritDoc}
 54      *
 55      * @implSpec
 56      * This implementation iterates over <tt>entrySet()</tt> searching
 57      * for an entry with the specified key.  If such an entry is found,
 58      * <tt>true</tt> is returned.  If the iteration terminates without
 59      * finding such an entry, <tt>false</tt> is returned.  Note that this
 60      * implementation requires linear time in the size of the map; many
 61      * implementations will override this method.
 62      *
 63      * @throws ClassCastException   {@inheritDoc}
 64      * @throws NullPointerException {@inheritDoc}
 65      */
 66     public boolean containsKey(Object key) {
 67         Iterator<Map.Entry<K,V>> i = entrySet().iterator();
 68         if (key==null) {
 69             while (i.hasNext()) {
 70                 Entry<K,V> e = i.next();
 71                 if (e.getKey()==null)
 72                     return true;
 73             }
 74         } else {
 75             while (i.hasNext()) {
 76                 Entry<K,V> e = i.next();
 77                 if (key.equals(e.getKey()))
 78                     return true;
 79             }
 80         }
 81         return false;
 82     }
 83 
 84     /**
 85      * {@inheritDoc}
 86      *
 87      * @implSpec
 88      * This implementation iterates over <tt>entrySet()</tt> searching
 89      * for an entry with the specified key.  If such an entry is found,
 90      * the entry's value is returned.  If the iteration terminates without
 91      * finding such an entry, <tt>null</tt> is returned.  Note that this
 92      * implementation requires linear time in the size of the map; many
 93      * implementations will override this method.
 94      *
 95      * @throws ClassCastException            {@inheritDoc}
 96      * @throws NullPointerException          {@inheritDoc}
 97      */
 98     public V get(Object key) {
 99         Iterator<Entry<K,V>> i = entrySet().iterator();
100         if (key==null) {
101             while (i.hasNext()) {
102                 Entry<K,V> e = i.next();
103                 if (e.getKey()==null)
104                     return e.getValue();
105             }
106         } else {
107             while (i.hasNext()) {
108                 Entry<K,V> e = i.next();
109                 if (key.equals(e.getKey()))
110                     return e.getValue();
111             }
112         }
113         return null;
114     }
View Code

2.2 修改操作(Modification Operations)

 1 /**
 2      * {@inheritDoc}
 3      *
 4      * @implSpec
 5      * This implementation always throws an
 6      * <tt>UnsupportedOperationException</tt>.
 7      *
 8      * @throws UnsupportedOperationException {@inheritDoc}
 9      * @throws ClassCastException            {@inheritDoc}
10      * @throws NullPointerException          {@inheritDoc}
11      * @throws IllegalArgumentException      {@inheritDoc}
12      */
13     public V put(K key, V value) {
14         throw new UnsupportedOperationException();
15     }
16 
17     /**
18      * {@inheritDoc}
19      *
20      * @implSpec
21      * This implementation iterates over <tt>entrySet()</tt> searching for an
22      * entry with the specified key.  If such an entry is found, its value is
23      * obtained with its <tt>getValue</tt> operation, the entry is removed
24      * from the collection (and the backing map) with the iterator's
25      * <tt>remove</tt> operation, and the saved value is returned.  If the
26      * iteration terminates without finding such an entry, <tt>null</tt> is
27      * returned.  Note that this implementation requires linear time in the
28      * size of the map; many implementations will override this method.
29      *
30      * <p>Note that this implementation throws an
31      * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
32      * iterator does not support the <tt>remove</tt> method and this map
33      * contains a mapping for the specified key.
34      *
35      * @throws UnsupportedOperationException {@inheritDoc}
36      * @throws ClassCastException            {@inheritDoc}
37      * @throws NullPointerException          {@inheritDoc}
38      */
39     public V remove(Object key) {
40         Iterator<Entry<K,V>> i = entrySet().iterator();
41         Entry<K,V> correctEntry = null;
42         if (key==null) {
43             while (correctEntry==null && i.hasNext()) {
44                 Entry<K,V> e = i.next();
45                 if (e.getKey()==null)
46                     correctEntry = e;
47             }
48         } else {
49             while (correctEntry==null && i.hasNext()) {
50                 Entry<K,V> e = i.next();
51                 if (key.equals(e.getKey()))
52                     correctEntry = e;
53             }
54         }
55 
56         V oldValue = null;
57         if (correctEntry !=null) {
58             oldValue = correctEntry.getValue();
59             i.remove();
60         }
61         return oldValue;
62     }
View Code

2.3 批量操作(Bulk Operations)

 1 /**
 2      * {@inheritDoc}
 3      *
 4      * @implSpec
 5      * This implementation iterates over the specified map's
 6      * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
 7      * operation once for each entry returned by the iteration.
 8      *
 9      * <p>Note that this implementation throws an
10      * <tt>UnsupportedOperationException</tt> if this map does not support
11      * the <tt>put</tt> operation and the specified map is nonempty.
12      *
13      * @throws UnsupportedOperationException {@inheritDoc}
14      * @throws ClassCastException            {@inheritDoc}
15      * @throws NullPointerException          {@inheritDoc}
16      * @throws IllegalArgumentException      {@inheritDoc}
17      */
18     public void putAll(Map<? extends K, ? extends V> m) {
19         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
20             put(e.getKey(), e.getValue());
21     }
22 
23     /**
24      * {@inheritDoc}
25      *
26      * @implSpec
27      * This implementation calls <tt>entrySet().clear()</tt>.
28      *
29      * <p>Note that this implementation throws an
30      * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
31      * does not support the <tt>clear</tt> operation.
32      *
33      * @throws UnsupportedOperationException {@inheritDoc}
34      */
35     public void clear() {
36         entrySet().clear();
37     }
View Code

2.4 视图(Views)

  1 /**
  2      * Each of these fields are initialized to contain an instance of the
  3      * appropriate view the first time this view is requested.  The views are
  4      * stateless, so there's no reason to create more than one of each.
  5      *
  6      * <p>Since there is no synchronization performed while accessing these fields,
  7      * it is expected that java.util.Map view classes using these fields have
  8      * no non-final fields (or any fields at all except for outer-this). Adhering
  9      * to this rule would make the races on these fields benign.
 10      *
 11      * <p>It is also imperative that implementations read the field only once,
 12      * as in:
 13      *
 14      * <pre> {@code
 15      * public Set<K> keySet() {
 16      *   Set<K> ks = keySet;  // single racy read
 17      *   if (ks == null) {
 18      *     ks = new KeySet();
 19      *     keySet = ks;
 20      *   }
 21      *   return ks;
 22      * }
 23      *}</pre>
 24      */
 25     transient Set<K>        keySet;
 26     transient Collection<V> values;
 27 
 28     /**
 29      * {@inheritDoc}
 30      *
 31      * @implSpec
 32      * This implementation returns a set that subclasses {@link AbstractSet}.
 33      * The subclass's iterator method returns a "wrapper object" over this
 34      * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
 35      * delegates to this map's <tt>size</tt> method and the
 36      * <tt>contains</tt> method delegates to this map's
 37      * <tt>containsKey</tt> method.
 38      *
 39      * <p>The set is created the first time this method is called,
 40      * and returned in response to all subsequent calls.  No synchronization
 41      * is performed, so there is a slight chance that multiple calls to this
 42      * method will not all return the same set.
 43      */
 44     public Set<K> keySet() {
 45         Set<K> ks = keySet;
 46         if (ks == null) {
 47             ks = new AbstractSet<K>() {
 48                 public Iterator<K> iterator() {
 49                     return new Iterator<K>() {
 50                         private Iterator<Entry<K,V>> i = entrySet().iterator();
 51 
 52                         public boolean hasNext() {
 53                             return i.hasNext();
 54                         }
 55 
 56                         public K next() {
 57                             return i.next().getKey();
 58                         }
 59 
 60                         public void remove() {
 61                             i.remove();
 62                         }
 63                     };
 64                 }
 65 
 66                 public int size() {
 67                     return AbstractMap.this.size();
 68                 }
 69 
 70                 public boolean isEmpty() {
 71                     return AbstractMap.this.isEmpty();
 72                 }
 73 
 74                 public void clear() {
 75                     AbstractMap.this.clear();
 76                 }
 77 
 78                 public boolean contains(Object k) {
 79                     return AbstractMap.this.containsKey(k);
 80                 }
 81             };
 82             keySet = ks;
 83         }
 84         return ks;
 85     }
 86 
 87     /**
 88      * {@inheritDoc}
 89      *
 90      * @implSpec
 91      * This implementation returns a collection that subclasses {@link
 92      * AbstractCollection}.  The subclass's iterator method returns a
 93      * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
 94      * The <tt>size</tt> method delegates to this map's <tt>size</tt>
 95      * method and the <tt>contains</tt> method delegates to this map's
 96      * <tt>containsValue</tt> method.
 97      *
 98      * <p>The collection is created the first time this method is called, and
 99      * returned in response to all subsequent calls.  No synchronization is
100      * performed, so there is a slight chance that multiple calls to this
101      * method will not all return the same collection.
102      */
103     public Collection<V> values() {
104         Collection<V> vals = values;
105         if (vals == null) {
106             vals = new AbstractCollection<V>() {
107                 public Iterator<V> iterator() {
108                     return new Iterator<V>() {
109                         private Iterator<Entry<K,V>> i = entrySet().iterator();
110 
111                         public boolean hasNext() {
112                             return i.hasNext();
113                         }
114 
115                         public V next() {
116                             return i.next().getValue();
117                         }
118 
119                         public void remove() {
120                             i.remove();
121                         }
122                     };
123                 }
124 
125                 public int size() {
126                     return AbstractMap.this.size();
127                 }
128 
129                 public boolean isEmpty() {
130                     return AbstractMap.this.isEmpty();
131                 }
132 
133                 public void clear() {
134                     AbstractMap.this.clear();
135                 }
136 
137                 public boolean contains(Object v) {
138                     return AbstractMap.this.containsValue(v);
139                 }
140             };
141             values = vals;
142         }
143         return vals;
144     }
145 
146     public abstract Set<Entry<K,V>> entrySet();
View Code

2.5 比较和哈希(Comparison and hashing)

1 public boolean equals(Object o){}

比较函数在比较过程中分成几个步骤,或者说比较多个对象与该Map是否相等。

  1. o == this 传入的对象是否是该Map本身,是的话返回true
  2. 是否是Map的一个对象,否的话返回false
  3. 这是确定传入的o就是Map的一个实例化对象(成为o1),比较传入的对象与正在比较的Map实例化对象(o2)的大小是否相等,如果不相等返回false
  4. 这个时候比较o1和o2中的每对键值对是否相等,当存在key或者value不相等时返回false
  5. 此时确定o1和o2中的所有键值对相等,确定是具有两个相同值的Map,返回true
1 public int hashCode()

获取的是Map对象的哈希值,Map对象的哈希值为Map中的所有键值对的哈希值的和。

  1 /**
  2      * Compares the specified object with this map for equality.  Returns
  3      * <tt>true</tt> if the given object is also a map and the two maps
  4      * represent the same mappings.  More formally, two maps <tt>m1</tt> and
  5      * <tt>m2</tt> represent the same mappings if
  6      * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
  7      * <tt>equals</tt> method works properly across different implementations
  8      * of the <tt>Map</tt> interface.
  9      *
 10      * @implSpec
 11      * This implementation first checks if the specified object is this map;
 12      * if so it returns <tt>true</tt>.  Then, it checks if the specified
 13      * object is a map whose size is identical to the size of this map; if
 14      * not, it returns <tt>false</tt>.  If so, it iterates over this map's
 15      * <tt>entrySet</tt> collection, and checks that the specified map
 16      * contains each mapping that this map contains.  If the specified map
 17      * fails to contain such a mapping, <tt>false</tt> is returned.  If the
 18      * iteration completes, <tt>true</tt> is returned.
 19      *
 20      * @param o object to be compared for equality with this map
 21      * @return <tt>true</tt> if the specified object is equal to this map
 22      */
 23     public boolean equals(Object o) {
 24         if (o == this)
 25             return true;
 26 
 27         if (!(o instanceof Map))
 28             return false;
 29         Map<?,?> m = (Map<?,?>) o;
 30         if (m.size() != size())
 31             return false;
 32 
 33         try {
 34             Iterator<Entry<K,V>> i = entrySet().iterator();
 35             while (i.hasNext()) {
 36                 Entry<K,V> e = i.next();
 37                 K key = e.getKey();
 38                 V value = e.getValue();
 39                 if (value == null) {
 40                     if (!(m.get(key)==null && m.containsKey(key)))
 41                         return false;
 42                 } else {
 43                     if (!value.equals(m.get(key)))
 44                         return false;
 45                 }
 46             }
 47         } catch (ClassCastException unused) {
 48             return false;
 49         } catch (NullPointerException unused) {
 50             return false;
 51         }
 52 
 53         return true;
 54     }
 55 
 56     /**
 57      * Returns the hash code value for this map.  The hash code of a map is
 58      * defined to be the sum of the hash codes of each entry in the map's
 59      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
 60      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
 61      * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
 62      * {@link Object#hashCode}.
 63      *
 64      * @implSpec
 65      * This implementation iterates over <tt>entrySet()</tt>, calling
 66      * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
 67      * set, and adding up the results.
 68      *
 69      * @return the hash code value for this map
 70      * @see Map.Entry#hashCode()
 71      * @see Object#equals(Object)
 72      * @see Set#equals(Object)
 73      */
 74     public int hashCode() {
 75         int h = 0;
 76         Iterator<Entry<K,V>> i = entrySet().iterator();
 77         while (i.hasNext())
 78             h += i.next().hashCode();
 79         return h;
 80     }
 81 
 82     /**
 83      * Returns a string representation of this map.  The string representation
 84      * consists of a list of key-value mappings in the order returned by the
 85      * map's <tt>entrySet</tt> view's iterator, enclosed in braces
 86      * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
 87      * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
 88      * the key followed by an equals sign (<tt>"="</tt>) followed by the
 89      * associated value.  Keys and values are converted to strings as by
 90      * {@link String#valueOf(Object)}.
 91      *
 92      * @return a string representation of this map
 93      */
 94     public String toString() {
 95         Iterator<Entry<K,V>> i = entrySet().iterator();
 96         if (! i.hasNext())
 97             return "{}";
 98 
 99         StringBuilder sb = new StringBuilder();
100         sb.append('{');
101         for (;;) {
102             Entry<K,V> e = i.next();
103             K key = e.getKey();
104             V value = e.getValue();
105             sb.append(key   == this ? "(this Map)" : key);
106             sb.append('=');
107             sb.append(value == this ? "(this Map)" : value);
108             if (! i.hasNext())
109                 return sb.append('}').toString();
110             sb.append(',').append(' ');
111         }
112     }
113 
114     /**
115      * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
116      * and values themselves are not cloned.
117      *
118      * @return a shallow copy of this map
119      */
120     protected Object clone() throws CloneNotSupportedException {
121         AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
122         result.keySet = null;
123         result.values = null;
124         return result;
125     }
126 
127     /**
128      * Utility method for SimpleEntry and SimpleImmutableEntry.
129      * Test for equality, checking for nulls.
130      *
131      * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
132      */
133     private static boolean eq(Object o1, Object o2) {
134         return o1 == null ? o2 == null : o1.equals(o2);
135     }
136 
137     // Implementation Note: SimpleEntry and SimpleImmutableEntry
138     // are distinct unrelated classes, even though they share
139     // some code. Since you can't add or subtract final-ness
140     // of a field in a subclass, they can't share representations,
141     // and the amount of duplicated code is too small to warrant
142     // exposing a common abstract class.
143 
144 
145     /**
146      * An Entry maintaining a key and a value.  The value may be
147      * changed using the <tt>setValue</tt> method.  This class
148      * facilitates the process of building custom map
149      * implementations. For example, it may be convenient to return
150      * arrays of <tt>SimpleEntry</tt> instances in method
151      * <tt>Map.entrySet().toArray</tt>.
152      *
153      * @since 1.6
154      */
155     public static class SimpleEntry<K,V>
156         implements Entry<K,V>, java.io.Serializable
157     {
158         private static final long serialVersionUID = -8499721149061103585L;
159 
160         private final K key;
161         private V value;
162 
163         /**
164          * Creates an entry representing a mapping from the specified
165          * key to the specified value.
166          *
167          * @param key the key represented by this entry
168          * @param value the value represented by this entry
169          */
170         public SimpleEntry(K key, V value) {
171             this.key   = key;
172             this.value = value;
173         }
174 
175         /**
176          * Creates an entry representing the same mapping as the
177          * specified entry.
178          *
179          * @param entry the entry to copy
180          */
181         public SimpleEntry(Entry<? extends K, ? extends V> entry) {
182             this.key   = entry.getKey();
183             this.value = entry.getValue();
184         }
185 
186         /**
187          * Returns the key corresponding to this entry.
188          *
189          * @return the key corresponding to this entry
190          */
191         public K getKey() {
192             return key;
193         }
194 
195         /**
196          * Returns the value corresponding to this entry.
197          *
198          * @return the value corresponding to this entry
199          */
200         public V getValue() {
201             return value;
202         }
203 
204         /**
205          * Replaces the value corresponding to this entry with the specified
206          * value.
207          *
208          * @param value new value to be stored in this entry
209          * @return the old value corresponding to the entry
210          */
211         public V setValue(V value) {
212             V oldValue = this.value;
213             this.value = value;
214             return oldValue;
215         }
216 
217         /**
218          * Compares the specified object with this entry for equality.
219          * Returns {@code true} if the given object is also a map entry and
220          * the two entries represent the same mapping.  More formally, two
221          * entries {@code e1} and {@code e2} represent the same mapping
222          * if<pre>
223          *   (e1.getKey()==null ?
224          *    e2.getKey()==null :
225          *    e1.getKey().equals(e2.getKey()))
226          *   &amp;&amp;
227          *   (e1.getValue()==null ?
228          *    e2.getValue()==null :
229          *    e1.getValue().equals(e2.getValue()))</pre>
230          * This ensures that the {@code equals} method works properly across
231          * different implementations of the {@code Map.Entry} interface.
232          *
233          * @param o object to be compared for equality with this map entry
234          * @return {@code true} if the specified object is equal to this map
235          *         entry
236          * @see    #hashCode
237          */
238         public boolean equals(Object o) {
239             if (!(o instanceof Map.Entry))
240                 return false;
241             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
242             return eq(key, e.getKey()) && eq(value, e.getValue());
243         }
244 
245         /**
246          * Returns the hash code value for this map entry.  The hash code
247          * of a map entry {@code e} is defined to be: <pre>
248          *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
249          *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
250          * This ensures that {@code e1.equals(e2)} implies that
251          * {@code e1.hashCode()==e2.hashCode()} for any two Entries
252          * {@code e1} and {@code e2}, as required by the general
253          * contract of {@link Object#hashCode}.
254          *
255          * @return the hash code value for this map entry
256          * @see    #equals
257          */
258         public int hashCode() {
259             return (key   == null ? 0 :   key.hashCode()) ^
260                    (value == null ? 0 : value.hashCode());
261         }
262 
263         /**
264          * Returns a String representation of this map entry.  This
265          * implementation returns the string representation of this
266          * entry's key followed by the equals character ("<tt>=</tt>")
267          * followed by the string representation of this entry's value.
268          *
269          * @return a String representation of this map entry
270          */
271         public String toString() {
272             return key + "=" + value;
273         }
274 
275     }
276 
277     /**
278      * An Entry maintaining an immutable key and value.  This class
279      * does not support method <tt>setValue</tt>.  This class may be
280      * convenient in methods that return thread-safe snapshots of
281      * key-value mappings.
282      *
283      * @since 1.6
284      */
285     public static class SimpleImmutableEntry<K,V>
286         implements Entry<K,V>, java.io.Serializable
287     {
288         private static final long serialVersionUID = 7138329143949025153L;
289 
290         private final K key;
291         private final V value;
292 
293         /**
294          * Creates an entry representing a mapping from the specified
295          * key to the specified value.
296          *
297          * @param key the key represented by this entry
298          * @param value the value represented by this entry
299          */
300         public SimpleImmutableEntry(K key, V value) {
301             this.key   = key;
302             this.value = value;
303         }
304 
305         /**
306          * Creates an entry representing the same mapping as the
307          * specified entry.
308          *
309          * @param entry the entry to copy
310          */
311         public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
312             this.key   = entry.getKey();
313             this.value = entry.getValue();
314         }
315 
316         /**
317          * Returns the key corresponding to this entry.
318          *
319          * @return the key corresponding to this entry
320          */
321         public K getKey() {
322             return key;
323         }
324 
325         /**
326          * Returns the value corresponding to this entry.
327          *
328          * @return the value corresponding to this entry
329          */
330         public V getValue() {
331             return value;
332         }
333 
334         /**
335          * Replaces the value corresponding to this entry with the specified
336          * value (optional operation).  This implementation simply throws
337          * <tt>UnsupportedOperationException</tt>, as this class implements
338          * an <i>immutable</i> map entry.
339          *
340          * @param value new value to be stored in this entry
341          * @return (Does not return)
342          * @throws UnsupportedOperationException always
343          */
344         public V setValue(V value) {
345             throw new UnsupportedOperationException();
346         }
347 
348         /**
349          * Compares the specified object with this entry for equality.
350          * Returns {@code true} if the given object is also a map entry and
351          * the two entries represent the same mapping.  More formally, two
352          * entries {@code e1} and {@code e2} represent the same mapping
353          * if<pre>
354          *   (e1.getKey()==null ?
355          *    e2.getKey()==null :
356          *    e1.getKey().equals(e2.getKey()))
357          *   &amp;&amp;
358          *   (e1.getValue()==null ?
359          *    e2.getValue()==null :
360          *    e1.getValue().equals(e2.getValue()))</pre>
361          * This ensures that the {@code equals} method works properly across
362          * different implementations of the {@code Map.Entry} interface.
363          *
364          * @param o object to be compared for equality with this map entry
365          * @return {@code true} if the specified object is equal to this map
366          *         entry
367          * @see    #hashCode
368          */
369         public boolean equals(Object o) {
370             if (!(o instanceof Map.Entry))
371                 return false;
372             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
373             return eq(key, e.getKey()) && eq(value, e.getValue());
374         }
375 
376         /**
377          * Returns the hash code value for this map entry.  The hash code
378          * of a map entry {@code e} is defined to be: <pre>
379          *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
380          *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
381          * This ensures that {@code e1.equals(e2)} implies that
382          * {@code e1.hashCode()==e2.hashCode()} for any two Entries
383          * {@code e1} and {@code e2}, as required by the general
384          * contract of {@link Object#hashCode}.
385          *
386          * @return the hash code value for this map entry
387          * @see    #equals
388          */
389         public int hashCode() {
390             return (key   == null ? 0 :   key.hashCode()) ^
391                    (value == null ? 0 : value.hashCode());
392         }
393 
394         /**
395          * Returns a String representation of this map entry.  This
396          * implementation returns the string representation of this
397          * entry's key followed by the equals character ("<tt>=</tt>")
398          * followed by the string representation of this entry's value.
399          *
400          * @return a String representation of this map entry
401          */
402         public String toString() {
403             return key + "=" + value;
404         }
405 
406     }
View Code

待续

posted @ 2019-12-20 02:32  子春十一  阅读(497)  评论(0)    收藏  举报