1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 import java.io.Serializable; 21 22 /** 23 * A base class for {@code Map} implementations. 24 * 25 * <p>Subclasses that permit new mappings to be added must override {@link 26 * #put}. 27 * 28 * <p>The default implementations of many methods are inefficient for large 29 * maps. For example in the default implementation, each call to {@link #get} 30 * performs a linear iteration of the entry set. Subclasses should override such 31 * methods to improve their performance. 32 * 33 * @since 1.2 34 */ 35 public abstract class AbstractMap<K, V> implements Map<K, V> { 36 37 // Lazily initialized key set. 38 Set<K> keySet; 39 40 Collection<V> valuesCollection; 41 42 /** 43 * An immutable key-value mapping. Despite the name, this class is non-final 44 * and its subclasses may be mutable. 45 * 46 * @since 1.6 47 */ 48 public static class SimpleImmutableEntry<K, V> 49 implements Map.Entry<K, V>, Serializable { 50 private static final long serialVersionUID = 7138329143949025153L; 51 52 private final K key; 53 private final V value; 54 SimpleImmutableEntry(K theKey, V theValue)55 public SimpleImmutableEntry(K theKey, V theValue) { 56 key = theKey; 57 value = theValue; 58 } 59 60 /** 61 * Constructs an instance with the key and value of {@code copyFrom}. 62 */ SimpleImmutableEntry(Map.Entry<? extends K, ? extends V> copyFrom)63 public SimpleImmutableEntry(Map.Entry<? extends K, ? extends V> copyFrom) { 64 key = copyFrom.getKey(); 65 value = copyFrom.getValue(); 66 } 67 getKey()68 public K getKey() { 69 return key; 70 } 71 getValue()72 public V getValue() { 73 return value; 74 } 75 76 /** 77 * This base implementation throws {@code UnsupportedOperationException} 78 * always. 79 */ setValue(V object)80 public V setValue(V object) { 81 throw new UnsupportedOperationException(); 82 } 83 equals(Object object)84 @Override public boolean equals(Object object) { 85 if (this == object) { 86 return true; 87 } 88 if (object instanceof Map.Entry) { 89 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; 90 return (key == null ? entry.getKey() == null : key.equals(entry 91 .getKey())) 92 && (value == null ? entry.getValue() == null : value 93 .equals(entry.getValue())); 94 } 95 return false; 96 } 97 hashCode()98 @Override public int hashCode() { 99 return (key == null ? 0 : key.hashCode()) 100 ^ (value == null ? 0 : value.hashCode()); 101 } 102 toString()103 @Override public String toString() { 104 return key + "=" + value; 105 } 106 } 107 108 /** 109 * A key-value mapping with mutable values. 110 * 111 * @since 1.6 112 */ 113 public static class SimpleEntry<K, V> 114 implements Map.Entry<K, V>, Serializable { 115 private static final long serialVersionUID = -8499721149061103585L; 116 117 private final K key; 118 private V value; 119 SimpleEntry(K theKey, V theValue)120 public SimpleEntry(K theKey, V theValue) { 121 key = theKey; 122 value = theValue; 123 } 124 125 /** 126 * Constructs an instance with the key and value of {@code copyFrom}. 127 */ SimpleEntry(Map.Entry<? extends K, ? extends V> copyFrom)128 public SimpleEntry(Map.Entry<? extends K, ? extends V> copyFrom) { 129 key = copyFrom.getKey(); 130 value = copyFrom.getValue(); 131 } 132 getKey()133 public K getKey() { 134 return key; 135 } 136 getValue()137 public V getValue() { 138 return value; 139 } 140 setValue(V object)141 public V setValue(V object) { 142 V result = value; 143 value = object; 144 return result; 145 } 146 equals(Object object)147 @Override public boolean equals(Object object) { 148 if (this == object) { 149 return true; 150 } 151 if (object instanceof Map.Entry) { 152 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object; 153 return (key == null ? entry.getKey() == null : key.equals(entry 154 .getKey())) 155 && (value == null ? entry.getValue() == null : value 156 .equals(entry.getValue())); 157 } 158 return false; 159 } 160 hashCode()161 @Override public int hashCode() { 162 return (key == null ? 0 : key.hashCode()) 163 ^ (value == null ? 0 : value.hashCode()); 164 } 165 toString()166 @Override public String toString() { 167 return key + "=" + value; 168 } 169 } 170 AbstractMap()171 protected AbstractMap() { 172 } 173 174 /** 175 * {@inheritDoc} 176 * 177 * <p>This implementation calls {@code entrySet().clear()}. 178 */ clear()179 public void clear() { 180 entrySet().clear(); 181 } 182 183 /** 184 * {@inheritDoc} 185 * 186 * <p>This implementation iterates its key set, looking for a key that 187 * {@code key} equals. 188 */ containsKey(Object key)189 public boolean containsKey(Object key) { 190 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 191 if (key != null) { 192 while (it.hasNext()) { 193 if (key.equals(it.next().getKey())) { 194 return true; 195 } 196 } 197 } else { 198 while (it.hasNext()) { 199 if (it.next().getKey() == null) { 200 return true; 201 } 202 } 203 } 204 return false; 205 } 206 207 /** 208 * {@inheritDoc} 209 * 210 * <p>This implementation iterates its entry set, looking for an entry with 211 * a value that {@code value} equals. 212 */ containsValue(Object value)213 public boolean containsValue(Object value) { 214 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 215 if (value != null) { 216 while (it.hasNext()) { 217 if (value.equals(it.next().getValue())) { 218 return true; 219 } 220 } 221 } else { 222 while (it.hasNext()) { 223 if (it.next().getValue() == null) { 224 return true; 225 } 226 } 227 } 228 return false; 229 } 230 entrySet()231 public abstract Set<Map.Entry<K, V>> entrySet(); 232 233 /** 234 * {@inheritDoc} 235 * 236 * <p>This implementation first checks the structure of {@code object}. If 237 * it is not a map or of a different size, this returns false. Otherwise it 238 * iterates its own entry set, looking up each entry's key in {@code 239 * object}. If any value does not equal the other map's value for the same 240 * key, this returns false. Otherwise it returns true. 241 */ equals(Object object)242 @Override public boolean equals(Object object) { 243 if (this == object) { 244 return true; 245 } 246 if (object instanceof Map) { 247 Map<?, ?> map = (Map<?, ?>) object; 248 if (size() != map.size()) { 249 return false; 250 } 251 252 try { 253 for (Entry<K, V> entry : entrySet()) { 254 K key = entry.getKey(); 255 V mine = entry.getValue(); 256 Object theirs = map.get(key); 257 if (mine == null) { 258 if (theirs != null || !map.containsKey(key)) { 259 return false; 260 } 261 } else if (!mine.equals(theirs)) { 262 return false; 263 } 264 } 265 } catch (NullPointerException ignored) { 266 return false; 267 } catch (ClassCastException ignored) { 268 return false; 269 } 270 return true; 271 } 272 return false; 273 } 274 275 /** 276 * {@inheritDoc} 277 * 278 * <p>This implementation iterates its entry set, looking for an entry with 279 * a key that {@code key} equals. 280 */ get(Object key)281 public V get(Object key) { 282 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 283 if (key != null) { 284 while (it.hasNext()) { 285 Map.Entry<K, V> entry = it.next(); 286 if (key.equals(entry.getKey())) { 287 return entry.getValue(); 288 } 289 } 290 } else { 291 while (it.hasNext()) { 292 Map.Entry<K, V> entry = it.next(); 293 if (entry.getKey() == null) { 294 return entry.getValue(); 295 } 296 } 297 } 298 return null; 299 } 300 301 /** 302 * {@inheritDoc} 303 * 304 * <p>This implementation iterates its entry set, summing the hashcodes of 305 * its entries. 306 */ hashCode()307 @Override public int hashCode() { 308 int result = 0; 309 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 310 while (it.hasNext()) { 311 result += it.next().hashCode(); 312 } 313 return result; 314 } 315 316 /** 317 * {@inheritDoc} 318 * 319 * <p>This implementation compares {@code size()} to 0. 320 */ isEmpty()321 public boolean isEmpty() { 322 return size() == 0; 323 } 324 325 /** 326 * {@inheritDoc} 327 * 328 * <p>This implementation returns a view that calls through this to map. Its 329 * iterator transforms this map's entry set iterator to return keys. 330 */ keySet()331 public Set<K> keySet() { 332 if (keySet == null) { 333 keySet = new AbstractSet<K>() { 334 @Override public boolean contains(Object object) { 335 return containsKey(object); 336 } 337 338 @Override public int size() { 339 return AbstractMap.this.size(); 340 } 341 342 @Override public Iterator<K> iterator() { 343 return new Iterator<K>() { 344 Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator(); 345 346 public boolean hasNext() { 347 return setIterator.hasNext(); 348 } 349 350 public K next() { 351 return setIterator.next().getKey(); 352 } 353 354 public void remove() { 355 setIterator.remove(); 356 } 357 }; 358 } 359 }; 360 } 361 return keySet; 362 } 363 364 /** 365 * {@inheritDoc} 366 * 367 * <p>This base implementation throws {@code UnsupportedOperationException}. 368 */ put(K key, V value)369 public V put(K key, V value) { 370 throw new UnsupportedOperationException(); 371 } 372 373 /** 374 * {@inheritDoc} 375 * 376 * <p>This implementation iterates through {@code map}'s entry set, calling 377 * {@code put()} for each. 378 */ putAll(Map<? extends K, ? extends V> map)379 public void putAll(Map<? extends K, ? extends V> map) { 380 for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { 381 put(entry.getKey(), entry.getValue()); 382 } 383 } 384 385 /** 386 * {@inheritDoc} 387 * 388 * <p>This implementation iterates its entry set, removing the entry with 389 * a key that {@code key} equals. 390 */ remove(Object key)391 public V remove(Object key) { 392 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 393 if (key != null) { 394 while (it.hasNext()) { 395 Map.Entry<K, V> entry = it.next(); 396 if (key.equals(entry.getKey())) { 397 it.remove(); 398 return entry.getValue(); 399 } 400 } 401 } else { 402 while (it.hasNext()) { 403 Map.Entry<K, V> entry = it.next(); 404 if (entry.getKey() == null) { 405 it.remove(); 406 return entry.getValue(); 407 } 408 } 409 } 410 return null; 411 } 412 413 /** 414 * {@inheritDoc} 415 * 416 * <p>This implementation returns its entry set's size. 417 */ size()418 public int size() { 419 return entrySet().size(); 420 } 421 422 /** 423 * {@inheritDoc} 424 * 425 * <p>This implementation composes a string by iterating its entry set. If 426 * this map contains itself as a key or a value, the string "(this Map)" 427 * will appear in its place. 428 */ toString()429 @Override public String toString() { 430 if (isEmpty()) { 431 return "{}"; 432 } 433 434 StringBuilder buffer = new StringBuilder(size() * 28); 435 buffer.append('{'); 436 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 437 while (it.hasNext()) { 438 Map.Entry<K, V> entry = it.next(); 439 Object key = entry.getKey(); 440 if (key != this) { 441 buffer.append(key); 442 } else { 443 buffer.append("(this Map)"); 444 } 445 buffer.append('='); 446 Object value = entry.getValue(); 447 if (value != this) { 448 buffer.append(value); 449 } else { 450 buffer.append("(this Map)"); 451 } 452 if (it.hasNext()) { 453 buffer.append(", "); 454 } 455 } 456 buffer.append('}'); 457 return buffer.toString(); 458 } 459 460 /** 461 * {@inheritDoc} 462 * 463 * <p>This implementation returns a view that calls through this to map. Its 464 * iterator transforms this map's entry set iterator to return values. 465 */ values()466 public Collection<V> values() { 467 if (valuesCollection == null) { 468 valuesCollection = new AbstractCollection<V>() { 469 @Override public int size() { 470 return AbstractMap.this.size(); 471 } 472 473 @Override public boolean contains(Object object) { 474 return containsValue(object); 475 } 476 477 @Override public Iterator<V> iterator() { 478 return new Iterator<V>() { 479 Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator(); 480 481 public boolean hasNext() { 482 return setIterator.hasNext(); 483 } 484 485 public V next() { 486 return setIterator.next().getValue(); 487 } 488 489 public void remove() { 490 setIterator.remove(); 491 } 492 }; 493 } 494 }; 495 } 496 return valuesCollection; 497 } 498 499 @SuppressWarnings("unchecked") clone()500 @Override protected Object clone() throws CloneNotSupportedException { 501 AbstractMap<K, V> result = (AbstractMap<K, V>) super.clone(); 502 result.keySet = null; 503 result.valuesCollection = null; 504 return result; 505 } 506 } 507