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 */
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 }
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 }
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 }
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();
2.5 比较和哈希(Comparison and hashing)
1 public boolean equals(Object o){}
比较函数在比较过程中分成几个步骤,或者说比较多个对象与该Map是否相等。
- o == this 传入的对象是否是该Map本身,是的话返回true
- 是否是Map的一个对象,否的话返回false
- 这是确定传入的o就是Map的一个实例化对象(成为o1),比较传入的对象与正在比较的Map实例化对象(o2)的大小是否相等,如果不相等返回false
- 这个时候比较o1和o2中的每对键值对是否相等,当存在key或者value不相等时返回false
- 此时确定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 * && 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 * && 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 }
待续

浙公网安备 33010602011771号