• 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;
        }
    
  • 相关阅读:
    IE11 Promise对象未定义错误--解决方法
    HTML中 li 标签的value属性兼容问题
    Oracle--树形自关联表查询SQL
    SVNTortoise--Branche和Merge操作
    console--API
    前端自动分环境打包(vue和ant design)
    typeScript入门(四)泛型
    typeScript入门(三)接口
    typeScript入门(二)函数与类
    typeScript入门(一)构建环境和数据类型
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/10016034.html
Copyright © 2020-2023  润新知