枚举高性能之EnumMap


声明:本文转载自https://my.oschina.net/qixiaobo025/blog/1558664,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

背景

想必使用Java5之后枚举已经是每一个Java开发者很常用的工具了。特别是用来实现单例模式通过枚举也是一种推荐的方式。

大部分开发者也有根据枚举回去Map的需求。那么Jdk也提供了EnumMap这种便捷的工具类。

EnumMap内部通过数组【特定大小】比较高效和避免了冲突的方法完成更加方便安全和快捷的完成了枚举的map的构建。

源码

类图

构造函数

/**  * 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 <tt>keyType</tt> 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 <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; }

通常来说我们传递一个枚举类作为构造函数的参数。

很明显EnumMap 使用了和枚举数目长度大小相同的数组

put

// 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  *     <tt>null</tt> if there was no mapping for key.  (A <tt>null</tt>  *     return can also indicate that the map previously associated  *     <tt>null</tt> 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); } /**  * 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); }

相比较其他map enumMap对key进行了类型检查 如果类型不对则直接抛出异常。

其次就是相比其他Map内存能够降低的关键

EnumMap使用了key.ordinal()作为数组下标【由于枚举的数量是有限的,因此在初始化的时候EnumMap就已经初始化了和枚举长度相同的数组】

直接以下标的形式进行读写 因此其内存占用率相比其他Map是比较低的,并没有存key~

当然需要注意一下如果value是null的话EnumMap使用了一个特殊的对象NULL

用这个对象可以用来区分是否包含对应的key

比如开发者调用put(Enum.XXX,null)

但是如果直接把null放入数组那么后面containsKey就无法判断了

get

/**  * 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); } /**  * Returns true if key is of the proper type to be a key in this  * enum map.  */ 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; }

由于实现了Map的get方法因此不能使用泛型为Object 这个在编译器就不会报错。

因此建议可以在使用之前由开发者自己判断一次类型

remove

/**  * 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  *     <tt>null</tt> if there was no entry for key.  (A <tt>null</tt>  *     return can also indicate that the map previously associated  *     <tt>null</tt> with the specified key.)  */ 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); }

因此都可以利用枚举的ordinal方法 仍然需要注意的是NULL

containsKey

/**  * Returns <tt>true</tt> if this map contains a mapping for the specified  * 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; }

正是由于put时value为空的时候放入了NULL对象 所以才可以用!=null 来判断是否包含key

iter

迭代器的时候则需要判断数组对应元素是否为空

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();     } }

这样就可以完成了EnumMap的迭代 和其他JCF的集合类似EnumMap也不是线程安全的,需要通过同步该集合来保证

本文发表于2017年10月31日 14:34
(c)注:本文转载自https://my.oschina.net/qixiaobo025/blog/1558664,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2565 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1