33 * of the keys in an enum map must come from a single enum type that is 34 * specified, explicitly or implicitly, when the map is created. Enum maps 35 * are represented internally as arrays. This representation is extremely 36 * compact and efficient. 37 * 38 * <p>Enum maps are maintained in the <i>natural order</i> of their keys 39 * (the order in which the enum constants are declared). This is reflected 40 * in the iterators returned by the collections views ({@link #keySet()}, 41 * {@link #entrySet()}, and {@link #values()}). 42 * 43 * <p>Iterators returned by the collection views are <i>weakly consistent</i>: 44 * they will never throw {@link ConcurrentModificationException} and they may 45 * or may not show the effects of any modifications to the map that occur while 46 * the iteration is in progress. 47 * 48 * <p>Null keys are not permitted. Attempts to insert a null key will 49 * throw {@link NullPointerException}. Attempts to test for the 50 * presence of a null key or to remove one will, however, function properly. 51 * Null values are permitted. 52 53 * <P>Like most collection implementations <tt>EnumMap</tt> is not 54 * synchronized. If multiple threads access an enum map concurrently, and at 55 * least one of the threads modifies the map, it should be synchronized 56 * externally. This is typically accomplished by synchronizing on some 57 * object that naturally encapsulates the enum map. If no such object exists, 58 * the map should be "wrapped" using the {@link Collections#synchronizedMap} 59 * method. This is best done at creation time, to prevent accidental 60 * unsynchronized access: 61 * 62 * <pre> 63 * Map<EnumKey, V> m 64 * = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...)); 65 * </pre> 66 * 67 * <p>Implementation note: All basic operations execute in constant time. 68 * They are likely (though not guaranteed) to be faster than their 69 * {@link HashMap} counterparts. 70 * 71 * <p>This class is a member of the 72 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 73 * Java Collections Framework</a>. 74 * 75 * @author Josh Bloch 76 * @see EnumSet 77 * @since 1.5 78 */ 79 public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> 80 implements java.io.Serializable, Cloneable 81 { 82 /** 83 * The <tt>Class</tt> object for the enum type of all the keys of this map. 84 * 85 * @serial 86 */ 87 private final Class<K> keyType; 88 89 /** 90 * All of the values comprising K. (Cached for performance.) 91 */ 92 private transient K[] keyUniverse; 93 94 /** 95 * Array representation of this map. The ith element is the value 96 * to which universe[i] is currently mapped, or null if it isn't 97 * mapped to anything, or NULL if it's mapped to null. 98 */ 99 private transient Object[] vals; 100 101 /** 102 * The number of mappings in this map. 103 */ 114 public String toString() { 115 return "java.util.EnumMap.NULL"; 116 } 117 }; 118 119 private Object maskNull(Object value) { 120 return (value == null ? NULL : value); 121 } 122 123 @SuppressWarnings("unchecked") 124 private V unmaskNull(Object value) { 125 return (V)(value == NULL ? null : value); 126 } 127 128 private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0]; 129 130 /** 131 * Creates an empty enum map with the specified key type. 132 * 133 * @param keyType the class object of the key type for this enum map 134 * @throws NullPointerException if <tt>keyType</tt> is null 135 */ 136 public EnumMap(Class<K> keyType) { 137 this.keyType = keyType; 138 keyUniverse = getKeyUniverse(keyType); 139 vals = new Object[keyUniverse.length]; 140 } 141 142 /** 143 * Creates an enum map with the same key type as the specified enum 144 * map, initially containing the same mappings (if any). 145 * 146 * @param m the enum map from which to initialize this enum map 147 * @throws NullPointerException if <tt>m</tt> is null 148 */ 149 public EnumMap(EnumMap<K, ? extends V> m) { 150 keyType = m.keyType; 151 keyUniverse = m.keyUniverse; 152 vals = m.vals.clone(); 153 size = m.size; 154 } 155 156 /** 157 * Creates an enum map initialized from the specified map. If the 158 * specified map is an <tt>EnumMap</tt> instance, this constructor behaves 159 * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map 160 * must contain at least one mapping (in order to determine the new 161 * enum map's key type). 162 * 163 * @param m the map from which to initialize this enum map 164 * @throws IllegalArgumentException if <tt>m</tt> is not an 165 * <tt>EnumMap</tt> instance and contains no mappings 166 * @throws NullPointerException if <tt>m</tt> is null 167 */ 168 public EnumMap(Map<K, ? extends V> m) { 169 if (m instanceof EnumMap) { 170 EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m; 171 keyType = em.keyType; 172 keyUniverse = em.keyUniverse; 173 vals = em.vals.clone(); 174 size = em.size; 175 } else { 176 if (m.isEmpty()) 177 throw new IllegalArgumentException("Specified map is empty"); 178 keyType = m.keySet().iterator().next().getDeclaringClass(); 179 keyUniverse = getKeyUniverse(keyType); 180 vals = new Object[keyUniverse.length]; 181 putAll(m); 182 } 183 } 184 185 // Query Operations 186 187 /** 188 * Returns the number of key-value mappings in this map. 189 * 190 * @return the number of key-value mappings in this map 191 */ 192 public int size() { 193 return size; 194 } 195 196 /** 197 * Returns <tt>true</tt> if this map maps one or more keys to the 198 * specified value. 199 * 200 * @param value the value whose presence in this map is to be tested 201 * @return <tt>true</tt> if this map maps one or more keys to this value 202 */ 203 public boolean containsValue(Object value) { 204 value = maskNull(value); 205 206 for (Object val : vals) 207 if (value.equals(val)) 208 return true; 209 210 return false; 211 } 212 213 /** 214 * Returns <tt>true</tt> if this map contains a mapping for the specified 215 * key. 216 * 217 * @param key the key whose presence in this map is to be tested 218 * @return <tt>true</tt> if this map contains a mapping for the specified 219 * key 220 */ 221 public boolean containsKey(Object key) { 222 return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null; 223 } 224 225 private boolean containsMapping(Object key, Object value) { 226 return isValidKey(key) && 227 maskNull(value).equals(vals[((Enum<?>)key).ordinal()]); 228 } 229 230 /** 231 * Returns the value to which the specified key is mapped, 232 * or {@code null} if this map contains no mapping for the key. 233 * 234 * <p>More formally, if this map contains a mapping from a key 235 * {@code k} to a value {@code v} such that {@code (key == k)}, 236 * then this method returns {@code v}; otherwise it returns 237 * {@code null}. (There can be at most one such mapping.) 238 * 241 * possible that the map explicitly maps the key to {@code null}. 242 * The {@link #containsKey containsKey} operation may be used to 243 * distinguish these two cases. 244 */ 245 public V get(Object key) { 246 return (isValidKey(key) ? 247 unmaskNull(vals[((Enum<?>)key).ordinal()]) : null); 248 } 249 250 // Modification Operations 251 252 /** 253 * Associates the specified value with the specified key in this map. 254 * If the map previously contained a mapping for this key, the old 255 * value is replaced. 256 * 257 * @param key the key with which the specified value is to be associated 258 * @param value the value to be associated with the specified key 259 * 260 * @return the previous value associated with specified key, or 261 * <tt>null</tt> if there was no mapping for key. (A <tt>null</tt> 262 * return can also indicate that the map previously associated 263 * <tt>null</tt> with the specified key.) 264 * @throws NullPointerException if the specified key is null 265 */ 266 public V put(K key, V value) { 267 typeCheck(key); 268 269 int index = key.ordinal(); 270 Object oldValue = vals[index]; 271 vals[index] = maskNull(value); 272 if (oldValue == null) 273 size++; 274 return unmaskNull(oldValue); 275 } 276 277 /** 278 * Removes the mapping for this key from this map if present. 279 * 280 * @param key the key whose mapping is to be removed from the map 281 * @return the previous value associated with specified key, or 282 * <tt>null</tt> if there was no entry for key. (A <tt>null</tt> 283 * return can also indicate that the map previously associated 284 * <tt>null</tt> with the specified key.) 285 */ 286 public V remove(Object key) { 287 if (!isValidKey(key)) 288 return null; 289 int index = ((Enum<?>)key).ordinal(); 290 Object oldValue = vals[index]; 291 vals[index] = null; 292 if (oldValue != null) 293 size--; 294 return unmaskNull(oldValue); 295 } 296 297 private boolean removeMapping(Object key, Object value) { 298 if (!isValidKey(key)) 299 return false; 300 int index = ((Enum<?>)key).ordinal(); 301 if (maskNull(value).equals(vals[index])) { 302 vals[index] = null; 303 size--; 304 return true; 627 628 public String toString() { 629 if (index < 0) 630 return super.toString(); 631 632 return keyUniverse[index] + "=" 633 + unmaskNull(vals[index]); 634 } 635 636 private void checkIndexForEntryUse() { 637 if (index < 0) 638 throw new IllegalStateException("Entry was removed"); 639 } 640 } 641 } 642 643 // Comparison and hashing 644 645 /** 646 * Compares the specified object with this map for equality. Returns 647 * <tt>true</tt> if the given object is also a map and the two maps 648 * represent the same mappings, as specified in the {@link 649 * Map#equals(Object)} contract. 650 * 651 * @param o the object to be compared for equality with this map 652 * @return <tt>true</tt> if the specified object is equal to this map 653 */ 654 public boolean equals(Object o) { 655 if (this == o) 656 return true; 657 if (o instanceof EnumMap) 658 return equals((EnumMap<?,?>)o); 659 if (!(o instanceof Map)) 660 return false; 661 662 Map<?,?> m = (Map<?,?>)o; 663 if (size != m.size()) 664 return false; 665 666 for (int i = 0; i < keyUniverse.length; i++) { 667 if (null != vals[i]) { 668 K key = keyUniverse[i]; 669 V value = unmaskNull(vals[i]); 670 if (null == value) { 671 if (!((null == m.get(key)) && m.containsKey(key))) 672 return false; 741 * Throws an exception if e is not of the correct type for this enum set. 742 */ 743 private void typeCheck(K key) { 744 Class<?> keyClass = key.getClass(); 745 if (keyClass != keyType && keyClass.getSuperclass() != keyType) 746 throw new ClassCastException(keyClass + " != " + keyType); 747 } 748 749 /** 750 * Returns all of the values comprising K. 751 * The result is uncloned, cached, and shared by all callers. 752 */ 753 private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) { 754 return SharedSecrets.getJavaLangAccess() 755 .getEnumConstantsShared(keyType); 756 } 757 758 private static final long serialVersionUID = 458661240069192865L; 759 760 /** 761 * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e., 762 * serialize it). 763 * 764 * @serialData The <i>size</i> of the enum map (the number of key-value 765 * mappings) is emitted (int), followed by the key (Object) 766 * and value (Object) for each key-value mapping represented 767 * by the enum map. 768 */ 769 private void writeObject(java.io.ObjectOutputStream s) 770 throws java.io.IOException 771 { 772 // Write out the key type and any hidden stuff 773 s.defaultWriteObject(); 774 775 // Write out size (number of Mappings) 776 s.writeInt(size); 777 778 // Write out keys and values (alternating) 779 int entriesToBeWritten = size; 780 for (int i = 0; entriesToBeWritten > 0; i++) { 781 if (null != vals[i]) { 782 s.writeObject(keyUniverse[i]); 783 s.writeObject(unmaskNull(vals[i])); 784 entriesToBeWritten--; 785 } 786 } 787 } 788 789 /** 790 * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e., 791 * deserialize it). 792 */ 793 @SuppressWarnings("unchecked") 794 private void readObject(java.io.ObjectInputStream s) 795 throws java.io.IOException, ClassNotFoundException 796 { 797 // Read in the key type and any hidden stuff 798 s.defaultReadObject(); 799 800 keyUniverse = getKeyUniverse(keyType); 801 vals = new Object[keyUniverse.length]; 802 803 // Read in size (number of Mappings) 804 int size = s.readInt(); 805 806 // Read the keys and values, and put the mappings in the HashMap 807 for (int i = 0; i < size; i++) { 808 K key = (K) s.readObject(); 809 V value = (V) s.readObject(); 810 put(key, value); | 33 * of the keys in an enum map must come from a single enum type that is 34 * specified, explicitly or implicitly, when the map is created. Enum maps 35 * are represented internally as arrays. This representation is extremely 36 * compact and efficient. 37 * 38 * <p>Enum maps are maintained in the <i>natural order</i> of their keys 39 * (the order in which the enum constants are declared). This is reflected 40 * in the iterators returned by the collections views ({@link #keySet()}, 41 * {@link #entrySet()}, and {@link #values()}). 42 * 43 * <p>Iterators returned by the collection views are <i>weakly consistent</i>: 44 * they will never throw {@link ConcurrentModificationException} and they may 45 * or may not show the effects of any modifications to the map that occur while 46 * the iteration is in progress. 47 * 48 * <p>Null keys are not permitted. Attempts to insert a null key will 49 * throw {@link NullPointerException}. Attempts to test for the 50 * presence of a null key or to remove one will, however, function properly. 51 * Null values are permitted. 52 53 * <P>Like most collection implementations {@code EnumMap} is not 54 * synchronized. If multiple threads access an enum map concurrently, and at 55 * least one of the threads modifies the map, it should be synchronized 56 * externally. This is typically accomplished by synchronizing on some 57 * object that naturally encapsulates the enum map. If no such object exists, 58 * the map should be "wrapped" using the {@link Collections#synchronizedMap} 59 * method. This is best done at creation time, to prevent accidental 60 * unsynchronized access: 61 * 62 * <pre> 63 * Map<EnumKey, V> m 64 * = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...)); 65 * </pre> 66 * 67 * <p>Implementation note: All basic operations execute in constant time. 68 * They are likely (though not guaranteed) to be faster than their 69 * {@link HashMap} counterparts. 70 * 71 * <p>This class is a member of the 72 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 73 * Java Collections Framework</a>. 74 * 75 * @author Josh Bloch 76 * @see EnumSet 77 * @since 1.5 78 */ 79 public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> 80 implements java.io.Serializable, Cloneable 81 { 82 /** 83 * The {@code Class} object for the enum type of all the keys of this map. 84 * 85 * @serial 86 */ 87 private final Class<K> keyType; 88 89 /** 90 * All of the values comprising K. (Cached for performance.) 91 */ 92 private transient K[] keyUniverse; 93 94 /** 95 * Array representation of this map. The ith element is the value 96 * to which universe[i] is currently mapped, or null if it isn't 97 * mapped to anything, or NULL if it's mapped to null. 98 */ 99 private transient Object[] vals; 100 101 /** 102 * The number of mappings in this map. 103 */ 114 public String toString() { 115 return "java.util.EnumMap.NULL"; 116 } 117 }; 118 119 private Object maskNull(Object value) { 120 return (value == null ? NULL : value); 121 } 122 123 @SuppressWarnings("unchecked") 124 private V unmaskNull(Object value) { 125 return (V)(value == NULL ? null : value); 126 } 127 128 private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0]; 129 130 /** 131 * Creates an empty enum map with the specified key type. 132 * 133 * @param keyType the class object of the key type for this enum map 134 * @throws NullPointerException if {@code keyType} is null 135 */ 136 public EnumMap(Class<K> keyType) { 137 this.keyType = keyType; 138 keyUniverse = getKeyUniverse(keyType); 139 vals = new Object[keyUniverse.length]; 140 } 141 142 /** 143 * Creates an enum map with the same key type as the specified enum 144 * map, initially containing the same mappings (if any). 145 * 146 * @param m the enum map from which to initialize this enum map 147 * @throws NullPointerException if {@code m} is null 148 */ 149 public EnumMap(EnumMap<K, ? extends V> m) { 150 keyType = m.keyType; 151 keyUniverse = m.keyUniverse; 152 vals = m.vals.clone(); 153 size = m.size; 154 } 155 156 /** 157 * Creates an enum map initialized from the specified map. If the 158 * specified map is an {@code EnumMap} instance, this constructor behaves 159 * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map 160 * must contain at least one mapping (in order to determine the new 161 * enum map's key type). 162 * 163 * @param m the map from which to initialize this enum map 164 * @throws IllegalArgumentException if {@code m} is not an 165 * {@code EnumMap} instance and contains no mappings 166 * @throws NullPointerException if {@code m} is null 167 */ 168 public EnumMap(Map<K, ? extends V> m) { 169 if (m instanceof EnumMap) { 170 EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m; 171 keyType = em.keyType; 172 keyUniverse = em.keyUniverse; 173 vals = em.vals.clone(); 174 size = em.size; 175 } else { 176 if (m.isEmpty()) 177 throw new IllegalArgumentException("Specified map is empty"); 178 keyType = m.keySet().iterator().next().getDeclaringClass(); 179 keyUniverse = getKeyUniverse(keyType); 180 vals = new Object[keyUniverse.length]; 181 putAll(m); 182 } 183 } 184 185 // Query Operations 186 187 /** 188 * Returns the number of key-value mappings in this map. 189 * 190 * @return the number of key-value mappings in this map 191 */ 192 public int size() { 193 return size; 194 } 195 196 /** 197 * Returns {@code true} if this map maps one or more keys to the 198 * specified value. 199 * 200 * @param value the value whose presence in this map is to be tested 201 * @return {@code true} if this map maps one or more keys to this value 202 */ 203 public boolean containsValue(Object value) { 204 value = maskNull(value); 205 206 for (Object val : vals) 207 if (value.equals(val)) 208 return true; 209 210 return false; 211 } 212 213 /** 214 * Returns {@code true} if this map contains a mapping for the specified 215 * key. 216 * 217 * @param key the key whose presence in this map is to be tested 218 * @return {@code true} if this map contains a mapping for the specified 219 * key 220 */ 221 public boolean containsKey(Object key) { 222 return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null; 223 } 224 225 private boolean containsMapping(Object key, Object value) { 226 return isValidKey(key) && 227 maskNull(value).equals(vals[((Enum<?>)key).ordinal()]); 228 } 229 230 /** 231 * Returns the value to which the specified key is mapped, 232 * or {@code null} if this map contains no mapping for the key. 233 * 234 * <p>More formally, if this map contains a mapping from a key 235 * {@code k} to a value {@code v} such that {@code (key == k)}, 236 * then this method returns {@code v}; otherwise it returns 237 * {@code null}. (There can be at most one such mapping.) 238 * 241 * possible that the map explicitly maps the key to {@code null}. 242 * The {@link #containsKey containsKey} operation may be used to 243 * distinguish these two cases. 244 */ 245 public V get(Object key) { 246 return (isValidKey(key) ? 247 unmaskNull(vals[((Enum<?>)key).ordinal()]) : null); 248 } 249 250 // Modification Operations 251 252 /** 253 * Associates the specified value with the specified key in this map. 254 * If the map previously contained a mapping for this key, the old 255 * value is replaced. 256 * 257 * @param key the key with which the specified value is to be associated 258 * @param value the value to be associated with the specified key 259 * 260 * @return the previous value associated with specified key, or 261 * {@code null} if there was no mapping for key. (A {@code null} 262 * return can also indicate that the map previously associated 263 * {@code null} with the specified key.) 264 * @throws NullPointerException if the specified key is null 265 */ 266 public V put(K key, V value) { 267 typeCheck(key); 268 269 int index = key.ordinal(); 270 Object oldValue = vals[index]; 271 vals[index] = maskNull(value); 272 if (oldValue == null) 273 size++; 274 return unmaskNull(oldValue); 275 } 276 277 /** 278 * Removes the mapping for this key from this map if present. 279 * 280 * @param key the key whose mapping is to be removed from the map 281 * @return the previous value associated with specified key, or 282 * {@code null} if there was no entry for key. (A {@code null} 283 * return can also indicate that the map previously associated 284 * {@code null} with the specified key.) 285 */ 286 public V remove(Object key) { 287 if (!isValidKey(key)) 288 return null; 289 int index = ((Enum<?>)key).ordinal(); 290 Object oldValue = vals[index]; 291 vals[index] = null; 292 if (oldValue != null) 293 size--; 294 return unmaskNull(oldValue); 295 } 296 297 private boolean removeMapping(Object key, Object value) { 298 if (!isValidKey(key)) 299 return false; 300 int index = ((Enum<?>)key).ordinal(); 301 if (maskNull(value).equals(vals[index])) { 302 vals[index] = null; 303 size--; 304 return true; 627 628 public String toString() { 629 if (index < 0) 630 return super.toString(); 631 632 return keyUniverse[index] + "=" 633 + unmaskNull(vals[index]); 634 } 635 636 private void checkIndexForEntryUse() { 637 if (index < 0) 638 throw new IllegalStateException("Entry was removed"); 639 } 640 } 641 } 642 643 // Comparison and hashing 644 645 /** 646 * Compares the specified object with this map for equality. Returns 647 * {@code true} if the given object is also a map and the two maps 648 * represent the same mappings, as specified in the {@link 649 * Map#equals(Object)} contract. 650 * 651 * @param o the object to be compared for equality with this map 652 * @return {@code true} if the specified object is equal to this map 653 */ 654 public boolean equals(Object o) { 655 if (this == o) 656 return true; 657 if (o instanceof EnumMap) 658 return equals((EnumMap<?,?>)o); 659 if (!(o instanceof Map)) 660 return false; 661 662 Map<?,?> m = (Map<?,?>)o; 663 if (size != m.size()) 664 return false; 665 666 for (int i = 0; i < keyUniverse.length; i++) { 667 if (null != vals[i]) { 668 K key = keyUniverse[i]; 669 V value = unmaskNull(vals[i]); 670 if (null == value) { 671 if (!((null == m.get(key)) && m.containsKey(key))) 672 return false; 741 * Throws an exception if e is not of the correct type for this enum set. 742 */ 743 private void typeCheck(K key) { 744 Class<?> keyClass = key.getClass(); 745 if (keyClass != keyType && keyClass.getSuperclass() != keyType) 746 throw new ClassCastException(keyClass + " != " + keyType); 747 } 748 749 /** 750 * Returns all of the values comprising K. 751 * The result is uncloned, cached, and shared by all callers. 752 */ 753 private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) { 754 return SharedSecrets.getJavaLangAccess() 755 .getEnumConstantsShared(keyType); 756 } 757 758 private static final long serialVersionUID = 458661240069192865L; 759 760 /** 761 * Save the state of the {@code EnumMap} instance to a stream (i.e., 762 * serialize it). 763 * 764 * @serialData The <i>size</i> of the enum map (the number of key-value 765 * mappings) is emitted (int), followed by the key (Object) 766 * and value (Object) for each key-value mapping represented 767 * by the enum map. 768 */ 769 private void writeObject(java.io.ObjectOutputStream s) 770 throws java.io.IOException 771 { 772 // Write out the key type and any hidden stuff 773 s.defaultWriteObject(); 774 775 // Write out size (number of Mappings) 776 s.writeInt(size); 777 778 // Write out keys and values (alternating) 779 int entriesToBeWritten = size; 780 for (int i = 0; entriesToBeWritten > 0; i++) { 781 if (null != vals[i]) { 782 s.writeObject(keyUniverse[i]); 783 s.writeObject(unmaskNull(vals[i])); 784 entriesToBeWritten--; 785 } 786 } 787 } 788 789 /** 790 * Reconstitute the {@code EnumMap} instance from a stream (i.e., 791 * deserialize it). 792 */ 793 @SuppressWarnings("unchecked") 794 private void readObject(java.io.ObjectInputStream s) 795 throws java.io.IOException, ClassNotFoundException 796 { 797 // Read in the key type and any hidden stuff 798 s.defaultReadObject(); 799 800 keyUniverse = getKeyUniverse(keyType); 801 vals = new Object[keyUniverse.length]; 802 803 // Read in size (number of Mappings) 804 int size = s.readInt(); 805 806 // Read the keys and values, and put the mappings in the HashMap 807 for (int i = 0; i < size; i++) { 808 K key = (K) s.readObject(); 809 V value = (V) s.readObject(); 810 put(key, value); |