EnumMap类源码解析

来源:互联网 发布:金尚网上商城项目源码 编辑:程序博客网 时间:2024/05/16 04:57

EnumMap
内部通过数组存在元素
key:表示的是枚举类型,这个类型要一样
用value存储枚举具体的存储值
通过ordinal方法,使得有序存储

package java.util;import java.util.Map.Entry;import sun.misc.SharedSecrets;/** * @author Josh Bloch * @see EnumSet * @since 1.5 */public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>    implements java.io.Serializable, Cloneable{    /**     * 类型     *     * @serial     */    private final Class<K> keyType;    /**     * key要是枚举类型     */    private transient K[] keyUniverse;    /**     *内部数组存储values     */    private transient Object[] vals;    /**     *map的大小     */    private transient int size = 0;    /**     * 空时候     */    private static final Object NULL = new Object() {        public int hashCode() {            return 0;        }        public String toString() {            return "java.util.EnumMap.NULL";        }    };    private Object maskNull(Object value) {        return (value == null ? NULL : value);    }    private V unmaskNull(Object value) {        return (V) (value == NULL ? null : value);    }    // 0 个元素的 Enum     private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];    /**     * 指定key类型的构造函数     *     * @param keyType the class object of the key type for this enum map     * @throws NullPointerException if <tt>keyType</tt> is null     */    public EnumMap(Class<K> keyType) {        this.keyType = keyType;        keyUniverse = getKeyUniverse(keyType);        vals = new Object[keyUniverse.length];    }    /**     * 创建一个enum map 和指定Enummap有相同的key类型,并用该map进行初始化     *     * @param m the enum map from which to initialize this enum map     * @throws NullPointerException if <tt>m</tt> is null     */    public EnumMap(EnumMap<K, ? extends V> m) {        keyType = m.keyType;        keyUniverse = m.keyUniverse;        vals = m.vals.clone();        size = m.size;    }    /**     * 利用指定map 创建一个enum map     *     * @param m the map from which to initialize this enum map     * @throws IllegalArgumentException if <tt>m</tt> is not an     *     <tt>EnumMap</tt> instance and contains no mappings     * @throws NullPointerException if <tt>m</tt> 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())                throw new IllegalArgumentException("Specified map is empty");            keyType = m.keySet().iterator().next().getDeclaringClass();            keyUniverse = getKeyUniverse(keyType);            vals = new Object[keyUniverse.length];            putAll(m);        }    }    // Query Operations    /**     * 元素个数     *     * @return the number of key-value mappings in this map     */    public int size() {        return size;    }    /**      * 是否包含value的元素 先验证是否是有效的value,在遍历     * @param value the value whose presence in this map is to be tested     * @return <tt>true</tt> if this map maps one or more keys to this value     */    public boolean containsValue(Object value) {        value = maskNull(value);        for (Object val : vals)            if (value.equals(val))                return true;        return false;    }    /**     *是否包含key 的元素,先验证是否是有效的key,再遍历     * @param key the key whose presence in this map is to be tested     * @return <tt>true</tt> if this map contains a mapping for the specified     *            key     */    public boolean containsKey(Object key) {        return isValidKey(key) && vals[((Enum)key).ordinal()] != null;    }    // 是否包含该元素     private boolean containsMapping(Object key, Object value) {        return isValidKey(key) &&            maskNull(value).equals(vals[((Enum)key).ordinal()]);    }    /**     * 获取key对应value      */    public V get(Object key) {        return (isValidKey(key) ?                unmaskNull(vals[((Enum)key).ordinal()]) : null);    }    // Modification Operations    /**     * 加入元素      * @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);    }    /**     * 删除元素     */    public V remove(Object key) {        if (!isValidKey(key))            return null;        int index = ((Enum)key).ordinal();        Object oldValue = vals[index];        vals[index] = null;        if (oldValue != null)            size--;        return unmaskNull(oldValue);    }    private boolean removeMapping(Object key, Object value) {        if (!isValidKey(key))            return false;        int index = ((Enum)key).ordinal();        if (maskNull(value).equals(vals[index])) {            vals[index] = null;            size--;            return true;        }        return false;    }    /**     *是否有效的key     */    private boolean isValidKey(Object key) {        if (key == null)            return false;        // Cheaper than instanceof Enum followed by getDeclaringClass        Class keyClass = key.getClass();        return keyClass == keyType || keyClass.getSuperclass() == keyType;    }    // Bulk Operations    /**     * map中元素加入到EnumMap     * @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     */    public void putAll(Map<? extends K, ? extends V> m) {        if (m instanceof EnumMap) {            EnumMap<? extends K, ? extends V> em =                (EnumMap<? extends K, ? extends V>)m;            if (em.keyType != keyType) {                if (em.isEmpty())                    return;                throw new 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);        }    }    /**     * 清空     */    public void clear() {        Arrays.fill(vals, null);        size = 0;    }    // Views    private transient Set<Map.Entry<K,V>> entrySet = null;    /**     * @return a set view of the keys contained in this enum map     */    public Set<K> keySet() {        Set<K> ks = keySet;        if (ks != null)            return ks;        else            return keySet = new KeySet();    }    private class KeySet extends AbstractSet<K> {        public Iterator<K> iterator() {            return new KeyIterator();        }        public int size() {            return size;        }        public boolean contains(Object o) {            return containsKey(o);        }        public boolean remove(Object o) {            int oldSize = size;            EnumMap.this.remove(o);            return size != oldSize;        }        public void clear() {            EnumMap.this.clear();        }    }    /**     * @return a collection view of the values contained in this map     */    public Collection<V> values() {        Collection<V> vs = values;        if (vs != null)            return vs;        else            return values = new Values();    }    private class Values extends AbstractCollection<V> {        public Iterator<V> iterator() {            return new ValueIterator();        }        public int size() {            return size;        }        public boolean contains(Object o) {            return containsValue(o);        }        public boolean remove(Object o) {            o = maskNull(o);            for (int i = 0; i < vals.length; i++) {                if (o.equals(vals[i])) {                    vals[i] = null;                    size--;                    return true;                }            }            return false;        }        public void clear() {            EnumMap.this.clear();        }    }    /**     * @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();    }    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {        public Iterator<Map.Entry<K,V>> iterator() {            return new EntryIterator();        }        public boolean contains(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry entry = (Map.Entry)o;            return containsMapping(entry.getKey(), entry.getValue());        }        public boolean remove(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry entry = (Map.Entry)o;            return removeMapping(entry.getKey(), entry.getValue());        }        public int size() {            return size;        }        public void clear() {            EnumMap.this.clear();        }        public Object[] toArray() {            return fillEntryArray(new Object[size]);        }        @SuppressWarnings("unchecked")        public <T> T[] toArray(T[] a) {            int size = size();            if (a.length < size)                a = (T[])java.lang.reflect.Array                    .newInstance(a.getClass().getComponentType(), size);            if (a.length > size)                a[size] = null;            return (T[]) fillEntryArray(a);        }        private Object[] fillEntryArray(Object[] a) {            int j = 0;            for (int i = 0; i < vals.length; i++)                if (vals[i] != null)                    a[j++] = new AbstractMap.SimpleEntry<>(                        keyUniverse[i], unmaskNull(vals[i]));            return a;        }    }    private abstract class EnumMapIterator<T> implements Iterator<T> {        // Lower bound on index of next element to return        int index = 0;        // Index of last returned element, or -1 if none        int lastReturnedIndex = -1;        public boolean hasNext() {            while (index < vals.length && vals[index] == null)                index++;            return index != vals.length;        }        public void remove() {            checkLastReturnedIndex();            if (vals[lastReturnedIndex] != null) {                vals[lastReturnedIndex] = null;                size--;            }            lastReturnedIndex = -1;        }        private void checkLastReturnedIndex() {            if (lastReturnedIndex < 0)                throw new IllegalStateException();        }    }    private class KeyIterator extends EnumMapIterator<K> {        public K next() {            if (!hasNext())                throw new NoSuchElementException();            lastReturnedIndex = index++;            return keyUniverse[lastReturnedIndex];        }    }    private class ValueIterator extends EnumMapIterator<V> {        public V next() {            if (!hasNext())                throw new NoSuchElementException();            lastReturnedIndex = index++;            return unmaskNull(vals[lastReturnedIndex]);        }    }    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {        private Entry lastReturnedEntry = null;        public Map.Entry<K,V> next() {            if (!hasNext())                throw new NoSuchElementException();            lastReturnedEntry = new Entry(index++);            return lastReturnedEntry;        }        public void remove() {            lastReturnedIndex =                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);            super.remove();            lastReturnedEntry.index = lastReturnedIndex;            lastReturnedEntry = null;        }        private class Entry implements Map.Entry<K,V> {            private int index;            private Entry(int index) {                this.index = index;            }            public K getKey() {                checkIndexForEntryUse();                return keyUniverse[index];            }            public V getValue() {                checkIndexForEntryUse();                return unmaskNull(vals[index]);            }            public V setValue(V value) {                checkIndexForEntryUse();                V oldValue = unmaskNull(vals[index]);                vals[index] = maskNull(value);                return oldValue;            }            public boolean equals(Object o) {                if (index < 0)                    return o == this;                if (!(o instanceof Map.Entry))                    return false;                Map.Entry e = (Map.Entry)o;                V ourValue = unmaskNull(vals[index]);                Object hisValue = e.getValue();                return (e.getKey() == keyUniverse[index] &&                        (ourValue == hisValue ||                         (ourValue != null && ourValue.equals(hisValue))));            }            public int hashCode() {                if (index < 0)                    return super.hashCode();                return entryHashCode(index);            }            public String toString() {                if (index < 0)                    return super.toString();                return keyUniverse[index] + "="                    + unmaskNull(vals[index]);            }            private void checkIndexForEntryUse() {                if (index < 0)                    throw new IllegalStateException("Entry was removed");            }        }    }    // Comparison and hashing    /**     * equals     */    public boolean equals(Object o) {        if (this == o)            return true;        if (o instanceof EnumMap)            return equals((EnumMap)o);        if (!(o instanceof Map))            return false;        Map<K,V> m = (Map<K,V>)o;        if (size != m.size())            return false;        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)))                       return false;                } else {                   if (!value.equals(m.get(key)))                      return false;                }            }        }        return true;    }    private boolean equals(EnumMap em) {        if (em.keyType != keyType)            return size == 0 && em.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)))                return false;        }        return true;    }    /**     * hashCode     */    public int hashCode() {        int h = 0;        for (int i = 0; i < keyUniverse.length; i++) {            if (null != vals[i]) {                h += entryHashCode(i);            }        }        return h;    }    private int entryHashCode(int index) {        return (keyUniverse[index].hashCode() ^ vals[index].hashCode());    }    /**     * clone     */    public EnumMap<K, V> clone() {        EnumMap<K, V> result = null;        try {            result = (EnumMap<K, V>) super.clone();        } catch(CloneNotSupportedException e) {            throw new 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.     */    private void typeCheck(K key) {        Class keyClass = key.getClass();        if (keyClass != keyType && keyClass.getSuperclass() != keyType)            throw new ClassCastException(keyClass + " != " + keyType);    }    /**     * Returns all of the values comprising K.     * The result is uncloned, cached, and shared by all callers.     */    private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {        return SharedSecrets.getJavaLangAccess()                                        .getEnumConstantsShared(keyType);    }    private static final long serialVersionUID = 458661240069192865L;    /**     * Save the state of the <tt>EnumMap</tt> 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.     */    private void 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 <tt>EnumMap</tt> instance from a stream (i.e.,     * deserialize it).     */    private void 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);        }    }}
0 0