48 * <p>Null keys are not permitted. Attempts to insert a null key will |
48 * <p>Null keys are not permitted. Attempts to insert a null key will |
49 * throw {@link NullPointerException}. Attempts to test for the |
49 * throw {@link NullPointerException}. Attempts to test for the |
50 * presence of a null key or to remove one will, however, function properly. |
50 * presence of a null key or to remove one will, however, function properly. |
51 * Null values are permitted. |
51 * Null values are permitted. |
52 |
52 |
53 * <P>Like most collection implementations <tt>EnumMap</tt> is not |
53 * <P>Like most collection implementations {@code EnumMap} is not |
54 * synchronized. If multiple threads access an enum map concurrently, and at |
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 |
55 * least one of the threads modifies the map, it should be synchronized |
56 * externally. This is typically accomplished by synchronizing on some |
56 * externally. This is typically accomplished by synchronizing on some |
57 * object that naturally encapsulates the enum map. If no such object exists, |
57 * object that naturally encapsulates the enum map. If no such object exists, |
58 * the map should be "wrapped" using the {@link Collections#synchronizedMap} |
58 * the map should be "wrapped" using the {@link Collections#synchronizedMap} |
78 */ |
78 */ |
79 public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> |
79 public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> |
80 implements java.io.Serializable, Cloneable |
80 implements java.io.Serializable, Cloneable |
81 { |
81 { |
82 /** |
82 /** |
83 * The <tt>Class</tt> object for the enum type of all the keys of this map. |
83 * The {@code Class} object for the enum type of all the keys of this map. |
84 * |
84 * |
85 * @serial |
85 * @serial |
86 */ |
86 */ |
87 private final Class<K> keyType; |
87 private final Class<K> keyType; |
88 |
88 |
129 |
129 |
130 /** |
130 /** |
131 * Creates an empty enum map with the specified key type. |
131 * Creates an empty enum map with the specified key type. |
132 * |
132 * |
133 * @param keyType the class object of the key type for this enum map |
133 * @param keyType the class object of the key type for this enum map |
134 * @throws NullPointerException if <tt>keyType</tt> is null |
134 * @throws NullPointerException if {@code keyType} is null |
135 */ |
135 */ |
136 public EnumMap(Class<K> keyType) { |
136 public EnumMap(Class<K> keyType) { |
137 this.keyType = keyType; |
137 this.keyType = keyType; |
138 keyUniverse = getKeyUniverse(keyType); |
138 keyUniverse = getKeyUniverse(keyType); |
139 vals = new Object[keyUniverse.length]; |
139 vals = new Object[keyUniverse.length]; |
142 /** |
142 /** |
143 * Creates an enum map with the same key type as the specified enum |
143 * Creates an enum map with the same key type as the specified enum |
144 * map, initially containing the same mappings (if any). |
144 * map, initially containing the same mappings (if any). |
145 * |
145 * |
146 * @param m the enum map from which to initialize this enum map |
146 * @param m the enum map from which to initialize this enum map |
147 * @throws NullPointerException if <tt>m</tt> is null |
147 * @throws NullPointerException if {@code m} is null |
148 */ |
148 */ |
149 public EnumMap(EnumMap<K, ? extends V> m) { |
149 public EnumMap(EnumMap<K, ? extends V> m) { |
150 keyType = m.keyType; |
150 keyType = m.keyType; |
151 keyUniverse = m.keyUniverse; |
151 keyUniverse = m.keyUniverse; |
152 vals = m.vals.clone(); |
152 vals = m.vals.clone(); |
153 size = m.size; |
153 size = m.size; |
154 } |
154 } |
155 |
155 |
156 /** |
156 /** |
157 * Creates an enum map initialized from the specified map. If the |
157 * Creates an enum map initialized from the specified map. If the |
158 * specified map is an <tt>EnumMap</tt> instance, this constructor behaves |
158 * specified map is an {@code EnumMap} instance, this constructor behaves |
159 * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map |
159 * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map |
160 * must contain at least one mapping (in order to determine the new |
160 * must contain at least one mapping (in order to determine the new |
161 * enum map's key type). |
161 * enum map's key type). |
162 * |
162 * |
163 * @param m the map from which to initialize this enum map |
163 * @param m the map from which to initialize this enum map |
164 * @throws IllegalArgumentException if <tt>m</tt> is not an |
164 * @throws IllegalArgumentException if {@code m} is not an |
165 * <tt>EnumMap</tt> instance and contains no mappings |
165 * {@code EnumMap} instance and contains no mappings |
166 * @throws NullPointerException if <tt>m</tt> is null |
166 * @throws NullPointerException if {@code m} is null |
167 */ |
167 */ |
168 public EnumMap(Map<K, ? extends V> m) { |
168 public EnumMap(Map<K, ? extends V> m) { |
169 if (m instanceof EnumMap) { |
169 if (m instanceof EnumMap) { |
170 EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m; |
170 EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m; |
171 keyType = em.keyType; |
171 keyType = em.keyType; |
192 public int size() { |
192 public int size() { |
193 return size; |
193 return size; |
194 } |
194 } |
195 |
195 |
196 /** |
196 /** |
197 * Returns <tt>true</tt> if this map maps one or more keys to the |
197 * Returns {@code true} if this map maps one or more keys to the |
198 * specified value. |
198 * specified value. |
199 * |
199 * |
200 * @param value the value whose presence in this map is to be tested |
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 |
201 * @return {@code true} if this map maps one or more keys to this value |
202 */ |
202 */ |
203 public boolean containsValue(Object value) { |
203 public boolean containsValue(Object value) { |
204 value = maskNull(value); |
204 value = maskNull(value); |
205 |
205 |
206 for (Object val : vals) |
206 for (Object val : vals) |
209 |
209 |
210 return false; |
210 return false; |
211 } |
211 } |
212 |
212 |
213 /** |
213 /** |
214 * Returns <tt>true</tt> if this map contains a mapping for the specified |
214 * Returns {@code true} if this map contains a mapping for the specified |
215 * key. |
215 * key. |
216 * |
216 * |
217 * @param key the key whose presence in this map is to be tested |
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 |
218 * @return {@code true} if this map contains a mapping for the specified |
219 * key |
219 * key |
220 */ |
220 */ |
221 public boolean containsKey(Object key) { |
221 public boolean containsKey(Object key) { |
222 return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null; |
222 return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null; |
223 } |
223 } |
256 * |
256 * |
257 * @param key the key with which the specified value is to be associated |
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 |
258 * @param value the value to be associated with the specified key |
259 * |
259 * |
260 * @return the previous value associated with specified key, or |
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> |
261 * {@code null} if there was no mapping for key. (A {@code null} |
262 * return can also indicate that the map previously associated |
262 * return can also indicate that the map previously associated |
263 * <tt>null</tt> with the specified key.) |
263 * {@code null} with the specified key.) |
264 * @throws NullPointerException if the specified key is null |
264 * @throws NullPointerException if the specified key is null |
265 */ |
265 */ |
266 public V put(K key, V value) { |
266 public V put(K key, V value) { |
267 typeCheck(key); |
267 typeCheck(key); |
268 |
268 |
277 /** |
277 /** |
278 * Removes the mapping for this key from this map if present. |
278 * Removes the mapping for this key from this map if present. |
279 * |
279 * |
280 * @param key the key whose mapping is to be removed from the map |
280 * @param key the key whose mapping is to be removed from the map |
281 * @return the previous value associated with specified key, or |
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> |
282 * {@code null} if there was no entry for key. (A {@code null} |
283 * return can also indicate that the map previously associated |
283 * return can also indicate that the map previously associated |
284 * <tt>null</tt> with the specified key.) |
284 * {@code null} with the specified key.) |
285 */ |
285 */ |
286 public V remove(Object key) { |
286 public V remove(Object key) { |
287 if (!isValidKey(key)) |
287 if (!isValidKey(key)) |
288 return null; |
288 return null; |
289 int index = ((Enum<?>)key).ordinal(); |
289 int index = ((Enum<?>)key).ordinal(); |
642 |
642 |
643 // Comparison and hashing |
643 // Comparison and hashing |
644 |
644 |
645 /** |
645 /** |
646 * Compares the specified object with this map for equality. Returns |
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 |
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 |
648 * represent the same mappings, as specified in the {@link |
649 * Map#equals(Object)} contract. |
649 * Map#equals(Object)} contract. |
650 * |
650 * |
651 * @param o the object to be compared for equality with this map |
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 |
652 * @return {@code true} if the specified object is equal to this map |
653 */ |
653 */ |
654 public boolean equals(Object o) { |
654 public boolean equals(Object o) { |
655 if (this == o) |
655 if (this == o) |
656 return true; |
656 return true; |
657 if (o instanceof EnumMap) |
657 if (o instanceof EnumMap) |
756 } |
756 } |
757 |
757 |
758 private static final long serialVersionUID = 458661240069192865L; |
758 private static final long serialVersionUID = 458661240069192865L; |
759 |
759 |
760 /** |
760 /** |
761 * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e., |
761 * Save the state of the {@code EnumMap} instance to a stream (i.e., |
762 * serialize it). |
762 * serialize it). |
763 * |
763 * |
764 * @serialData The <i>size</i> of the enum map (the number of key-value |
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) |
765 * mappings) is emitted (int), followed by the key (Object) |
766 * and value (Object) for each key-value mapping represented |
766 * and value (Object) for each key-value mapping represented |
785 } |
785 } |
786 } |
786 } |
787 } |
787 } |
788 |
788 |
789 /** |
789 /** |
790 * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e., |
790 * Reconstitute the {@code EnumMap} instance from a stream (i.e., |
791 * deserialize it). |
791 * deserialize it). |
792 */ |
792 */ |
793 @SuppressWarnings("unchecked") |
793 @SuppressWarnings("unchecked") |
794 private void readObject(java.io.ObjectInputStream s) |
794 private void readObject(java.io.ObjectInputStream s) |
795 throws java.io.IOException, ClassNotFoundException |
795 throws java.io.IOException, ClassNotFoundException |