/* * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
package java.util;
import jdk.internal.access.SharedSecrets;
/** * A specialized {@link Map} implementation for use with enum type keys. All * of the keys in an enum map must come from a single enum type that is * specified, explicitly or implicitly, when the map is created. Enum maps * are represented internally as arrays. This representation is extremely * compact and efficient. * * <p>Enum maps are maintained in the <i>natural order</i> of their keys * (the order in which the enum constants are declared). This is reflected * in the iterators returned by the collections views ({@link #keySet()}, * {@link #entrySet()}, and {@link #values()}). * * <p>Iterators returned by the collection views are <i>weakly consistent</i>: * they will never throw {@link ConcurrentModificationException} and they may * or may not show the effects of any modifications to the map that occur while * the iteration is in progress. * * <p>Null keys are not permitted. Attempts to insert a null key will * throw {@link NullPointerException}. Attempts to test for the * presence of a null key or to remove one will, however, function properly. * Null values are permitted. * * <P>Like most collection implementations {@code EnumMap} is not * synchronized. If multiple threads access an enum map concurrently, and at * least one of the threads modifies the map, it should be synchronized * externally. This is typically accomplished by synchronizing on some * object that naturally encapsulates the enum map. If no such object exists, * the map should be "wrapped" using the {@link Collections#synchronizedMap} * method. This is best done at creation time, to prevent accidental * unsynchronized access: * * <pre> * Map<EnumKey, V> m * = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...)); * </pre> * * <p>Implementation note: All basic operations execute in constant time. * They are likely (though not guaranteed) to be faster than their * {@link HashMap} counterparts. * * <p>This class is a member of the * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework"> * Java Collections Framework</a>. * * @param <K> the enum type of keys maintained by this map * @param <V> the type of mapped values * * @author Josh Bloch * @see EnumSet * @since 1.5
*/ publicclass EnumMap<K extendsEnum<K>, V> extends AbstractMap<K, V> implements java.io.Serializable, Cloneable
{ /** * The {@code Class} object for the enum type of all the keys of this map. * * @serial
*/ privatefinalClass<K> keyType;
/** * All of the values comprising K. (Cached for performance.)
*/ privatetransient K[] keyUniverse;
/** * Array representation of this map. The ith element is the value * to which universe[i] is currently mapped, or null if it isn't * mapped to anything, or NULL if it's mapped to null.
*/ privatetransient Object[] vals;
/** * The number of mappings in this map.
*/ privatetransientint size = 0;
/** * Distinguished non-null value for representing null values.
*/ privatestaticfinal Object NULL = new Object() { publicint hashCode() { return 0;
}
public String toString() { return"java.util.EnumMap.NULL";
}
};
/** * Creates an empty enum map with the specified key type. * * @param keyType the class object of the key type for this enum map * @throws NullPointerException if {@code keyType} is null
*/ public EnumMap(Class<K> keyType) { this.keyType = keyType;
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
}
/** * Creates an enum map with the same key type as the specified enum * map, initially containing the same mappings (if any). * * @param m the enum map from which to initialize this enum map * @throws NullPointerException if {@code m} is null
*/ public EnumMap(EnumMap<K, ? extends V> m) {
keyType = m.keyType;
keyUniverse = m.keyUniverse;
vals = m.vals.clone();
size = m.size;
}
/** * Creates an enum map initialized from the specified map. If the * specified map is an {@code EnumMap} instance, this constructor behaves * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map * must contain at least one mapping (in order to determine the new * enum map's key type). * * @param m the map from which to initialize this enum map * @throws IllegalArgumentException if {@code m} is not an * {@code EnumMap} instance and contains no mappings * @throws NullPointerException if {@code m} is null
*/ public EnumMap(Map<K, ? extends V> m) { if (m instanceof EnumMap) {
EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
keyType = em.keyType;
keyUniverse = em.keyUniverse;
vals = em.vals.clone();
size = em.size;
} else { if (m.isEmpty()) thrownew IllegalArgumentException("Specified map is empty");
keyType = m.keySet().iterator().next().getDeclaringClass();
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
putAll(m);
}
}
// Query Operations
/** * Returns the number of key-value mappings in this map. * * @return the number of key-value mappings in this map
*/ publicint size() { return size;
}
/** * Returns {@code true} if this map maps one or more keys to the * specified value. * * @param value the value whose presence in this map is to be tested * @return {@code true} if this map maps one or more keys to this value
*/ publicboolean containsValue(Object value) {
value = maskNull(value);
for (Object val : vals) if (value.equals(val)) returntrue;
returnfalse;
}
/** * Returns {@code true} if this map contains a mapping for the specified * key. * * @param key the key whose presence in this map is to be tested * @return {@code true} if this map contains a mapping for the specified * key
*/ publicboolean containsKey(Object key) { return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
/** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key == k)}, * then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code null} does not <i>necessarily</i> * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases.
*/ public V get(Object key) { return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
// Modification Operations
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for this key, the old * value is replaced. * * @param key the key with which the specified value is to be associated * @param value the value to be associated with the specified key * * @return the previous value associated with specified key, or * {@code null} if there was no mapping for key. (A {@code null} * return can also indicate that the map previously associated * {@code null} with the specified key.) * @throws NullPointerException if the specified key is null
*/ public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value); if (oldValue == null)
size++; return unmaskNull(oldValue);
}
/** * Removes the mapping for this key from this map if present. * * @param key the key whose mapping is to be removed from the map * @return the previous value associated with specified key, or * {@code null} if there was no entry for key. (A {@code null} * return can also indicate that the map previously associated * {@code null} with the specified key.)
*/ public V remove(Object key) { if (!isValidKey(key)) returnnull; int index = ((Enum<?>)key).ordinal();
Object oldValue = vals[index];
vals[index] = null; if (oldValue != null)
size--; return unmaskNull(oldValue);
}
privateboolean removeMapping(Object key, Object value) { if (!isValidKey(key)) returnfalse; int index = ((Enum<?>)key).ordinal(); if (maskNull(value).equals(vals[index])) {
vals[index] = null;
size--; returntrue;
} returnfalse;
}
/** * Returns true if key is of the proper type to be a key in this * enum map.
*/ privateboolean isValidKey(Object key) { if (key == null) returnfalse;
// Cheaper than instanceof Enum followed by getDeclaringClass Class<?> keyClass = key.getClass(); return keyClass == keyType || keyClass.getSuperclass() == keyType;
}
// Bulk Operations
/** * Copies all of the mappings from the specified map to this map. * These mappings will replace any mappings that this map had for * any of the keys currently in the specified map. * * @param m the mappings to be stored in this map * @throws NullPointerException the specified map is null, or if * one or more keys in the specified map are null
*/ publicvoid putAll(Map<? extends K, ? extends V> m) { if (m instanceof EnumMap<?, ?> em) { if (em.keyType != keyType) { if (em.isEmpty()) return; thrownew ClassCastException(em.keyType + " != " + keyType);
}
for (int i = 0; i < keyUniverse.length; i++) {
Object emValue = em.vals[i]; if (emValue != null) { if (vals[i] == null)
size++;
vals[i] = emValue;
}
}
} else { super.putAll(m);
}
}
/** * Removes all mappings from this map.
*/ publicvoid clear() {
Arrays.fill(vals, null);
size = 0;
}
// Views
/** * This field is initialized to contain an instance of the entry set * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one.
*/ privatetransient Set<Map.Entry<K,V>> entrySet;
/** * Returns a {@link Set} view of the keys contained in this map. * The returned set obeys the general contract outlined in * {@link Map#keySet()}. The set's iterator will return the keys * in their natural order (the order in which the enum constants * are declared). * * @return a set view of the keys contained in this enum map
*/ public Set<K> keySet() {
Set<K> ks = keySet; if (ks == null) {
ks = new KeySet();
keySet = ks;
} return ks;
}
/** * Returns a {@link Collection} view of the values contained in this map. * The returned collection obeys the general contract outlined in * {@link Map#values()}. The collection's iterator will return the * values in the order their corresponding keys appear in map, * which is their natural order (the order in which the enum constants * are declared). * * @return a collection view of the values contained in this map
*/ public Collection<V> values() {
Collection<V> vs = values; if (vs == null) {
vs = new Values();
values = vs;
} return vs;
}
for (int i = 0; i < vals.length; i++) { if (o.equals(vals[i])) {
vals[i] = null;
size--; returntrue;
}
} returnfalse;
} publicvoid clear() {
EnumMap.this.clear();
}
}
/** * Returns a {@link Set} view of the mappings contained in this map. * The returned set obeys the general contract outlined in * {@link Map#keySet()}. The set's iterator will return the * mappings in the order their keys appear in map, which is their * natural order (the order in which the enum constants are declared). * * @return a set view of the mappings contained in this enum map
*/ public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es = entrySet; if (es != null) return es; else return entrySet = new EntrySet();
}
privatevoid checkIndexForEntryUse() { if (index < 0) thrownew IllegalStateException("Entry was removed");
}
}
}
// Comparison and hashing
/** * Compares the specified object with this map for equality. Returns * {@code true} if the given object is also a map and the two maps * represent the same mappings, as specified in the {@link * Map#equals(Object)} contract. * * @param o the object to be compared for equality with this map * @return {@code true} if the specified object is equal to this map
*/ publicboolean equals(Object o) { if (this == o) returntrue; if (o instanceof EnumMap) return equals((EnumMap<?,?>)o); if (!(o instanceof Map<?, ?> m)) returnfalse;
if (size != m.size()) returnfalse;
for (int i = 0; i < keyUniverse.length; i++) { if (null != vals[i]) {
K key = keyUniverse[i];
V value = unmaskNull(vals[i]); if (null == value) { if (!((null == m.get(key)) && m.containsKey(key))) returnfalse;
} else { if (!value.equals(m.get(key))) returnfalse;
}
}
}
returntrue;
}
privateboolean equals(EnumMap<?,?> em) { if (em.size != size) returnfalse;
if (em.keyType != keyType) return size == 0;
// Key types match, compare each value for (int i = 0; i < keyUniverse.length; i++) {
Object ourValue = vals[i];
Object hisValue = em.vals[i]; if (hisValue != ourValue &&
(hisValue == null || !hisValue.equals(ourValue))) returnfalse;
} returntrue;
}
/** * Returns the hash code value for this map. The hash code of a map is * defined to be the sum of the hash codes of each entry in the map.
*/ publicint hashCode() { int h = 0;
for (int i = 0; i < keyUniverse.length; i++) { if (null != vals[i]) {
h += entryHashCode(i);
}
}
/** * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map
*/
@SuppressWarnings("unchecked") public EnumMap<K, V> clone() {
EnumMap<K, V> result = null; try {
result = (EnumMap<K, V>) super.clone();
} catch(CloneNotSupportedException e) { thrownew AssertionError();
}
result.vals = result.vals.clone();
result.entrySet = null; return result;
}
/** * Throws an exception if e is not of the correct type for this enum set.
*/ privatevoid typeCheck(K key) { Class<?> keyClass = key.getClass(); if (keyClass != keyType && keyClass.getSuperclass() != keyType) thrownew ClassCastException(keyClass + " != " + keyType);
}
/** * Returns all of the values comprising K. * The result is uncloned, cached, and shared by all callers.
*/ privatestatic <K extendsEnum<K>> K[] getKeyUniverse(Class<K> keyType) { return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(keyType);
}
/** * Save the state of the {@code EnumMap} instance to a stream (i.e., * serialize it). * * @serialData The <i>size</i> of the enum map (the number of key-value * mappings) is emitted (int), followed by the key (Object) * and value (Object) for each key-value mapping represented * by the enum map.
*/
@java.io.Serial privatevoid writeObject(java.io.ObjectOutputStream s) throws java.io.IOException
{ // Write out the key type and any hidden stuff
s.defaultWriteObject();
// Write out size (number of Mappings)
s.writeInt(size);
// Write out keys and values (alternating) int entriesToBeWritten = size; for (int i = 0; entriesToBeWritten > 0; i++) { if (null != vals[i]) {
s.writeObject(keyUniverse[i]);
s.writeObject(unmaskNull(vals[i]));
entriesToBeWritten--;
}
}
}
/** * Reconstitute the {@code EnumMap} instance from a stream (i.e., * deserialize it).
*/
@SuppressWarnings("unchecked")
@java.io.Serial privatevoid readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException
{ // Read in the key type and any hidden stuff
s.defaultReadObject();
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
// Read in size (number of Mappings) int size = s.readInt();
// Read the keys and values, and put the mappings in the HashMap for (int i = 0; i < size; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
put(key, value);
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.