• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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