zoukankan      html  css  js  c++  java
  • EnumMap 源码分析

    EnumMap

    EnumMap 能解决什么问题?什么时候使用 EnumMap?

    1)EnumMap【枚举映射】中的键值必须来自单个枚举。
    2)EnumMap 根据枚举键的自然顺序来维护,迭代遍历是有序的。
    3)不允许使用 null 键,允许使用 null 值,内部会进行 mask 处理。
    4)EnumMap 的键和值都通过对象数组来存储,读写性能高。
    

    如何使用 EnumMap?

    1)对象间映射关系的键来自单个枚举时,可以使用 EnumMap。
    

    使用 EnumMap 有什么风险?

    1)键和值的长度是根据枚举类型的元素个数确定的,可能存在一定的内存浪费。
    

    EnumMap 核心操作的实现原理?

    • 创建实例
        /**
         * 枚举键的 Class 类型
         */
        private final Class<K> keyType;
    
        /**
         * 枚举键的所有有效枚举值组成的数组
         */
        private transient K[] keyUniverse;
    
        /**
         * 底层存储值的对象数组
         */
        private transient Object[] vals;
    
        /**
         * 映射总数
         */
        private transient int size = 0;
    
        /**
         * 通过指定的键枚举类型创建空的枚举映射
         */
        public EnumMap(Class<K> keyType) {
            this.keyType = keyType;
            // 缓存所有的枚举值数组
            keyUniverse = EnumMap.getKeyUniverse(keyType);
            // 创建存储值的对象数组
            vals = new Object[keyUniverse.length];
        }
    
    • 添加元素
        private static final Object NULL = new Object() {
            @Override
            public int hashCode() {
                return 0;
            }
    
            @Override
            public String toString() {
                return "java.util.EnumMap.NULL";
            }
        };
    
        private Object maskNull(Object value) {
            return value == null ? NULL : value;
        }
    
        @SuppressWarnings("unchecked")
        private V unmaskNull(Object value) {
            return (V)(value == NULL ? null : value);
        }
    
        /**
         * 往枚举映射中添加元素
         */
        @Override
        public V put(K key, V value) {
            typeCheck(key);
    
            // 获取键的自然顺序
            final int index = key.ordinal();
            // 读取旧值
            final Object oldValue = vals[index];
            // 写入新值
            vals[index] = maskNull(value);
            // 如果之前为该 slot 为空
            if (oldValue == null) {
                // 则增加计数值
                size++;
            }
            // 返回 旧值
            return unmaskNull(oldValue);
        }
    
    • 读取元素
        /**
         * 根据目标键读取值
         */
        @Override
        public V get(Object key) {
            /**
             * 1)键合法则读取指定索引处的值,并 mask 后返回
             * 2)键非法则返回 null
             */
            return isValidKey(key) ?
                    unmaskNull(vals[((Enum<?>)key).ordinal()]) : null;
        }
    
        /**
         * 校验键是否合法
         */
        private boolean isValidKey(Object key) {
            // 枚举映射的键不能为 null
            if (key == null) {
                return false;
            }
    
            // Cheaper than instanceof Enum followed by getDeclaringClass
            // 校验键的类型是否合法
            final Class<?> keyClass = key.getClass();
            return keyClass == keyType || keyClass.getSuperclass() == keyType;
        }
    
    • 移除元素
        /**
         * 1)如果指定的枚举键存在,则移除并返回旧值
         * 2)否则返回 null
         */
        @Override
        public V remove(Object key) {
            // 1)键非法则返回 null
            if (!isValidKey(key)) {
                return null;
            }
            // 读取枚举键的自然顺序
            final int index = ((Enum<?>)key).ordinal();
            // 读取旧值
            final Object oldValue = vals[index];
            // 置空
            vals[index] = null;
            if (oldValue != null) {
                // 如果存在旧值,则递减元素总个数
                size--;
            }
            return unmaskNull(oldValue);
        }
    
    • 是否包含指定键
        /**
         * 枚举映射包含指定的键
         */
        @Override
        public boolean containsKey(Object key) {
            // 键合法并且以目标键的自然顺序为索引,读取 vals 中的值不为 null
            return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
        }
    
    • 是否包含指定值
        /**
         * 值数组中是否包含指定的值
         */
        @Override
        public boolean containsValue(Object value) {
            value = maskNull(value);
    
            for (final Object val : vals) {
                if (value.equals(val)) {
                    return true;
                }
            }
    
            return false;
        }
    
  • 相关阅读:
    致初学者:PHP比ASP优秀的七个理由
    有情人终成眷属为好友hualex2006.12.9结婚祝福
    有情人终成眷属为好友hualex2006.12.9结婚祝福
    各种查找算法效率比较
    实习三 树、二叉树及其应用 (题目:唯一地确定一棵二叉树 )
    hdu 2188 选拔志愿者(博弈)
    hdu 1050Moving Tables(贪心)
    实习一 线性表及其应用 (题目:一元稀疏多项式的加法运算 )
    实习六 农夫过河问题
    实习二 栈、队列和递归算法设计 (题目:停车场管理 )
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/10016034.html
Copyright © 2011-2022 走看看