zoukankan      html  css  js  c++  java
  • 容器--EnumMap

    一、概述

         EnumMap是一类特殊的Map, 其特殊之处在于KEY需要是枚举类型,由于枚举类型的特点是值的个数是固定的,所以,对于EnumMap来说,其所能存储的个数也就是固定的了。这种类型的Map相对来说是比较简单的。

    二、主要实现介绍

      1. 初始化

      由于EnumMap的enum特点,决定了其容器的容量是不变的,所以,在创建一个EnumMap的时候,我们就需要指定其大小,目前创建一个EnumMap主要有以下几种方式:

         public EnumMap(Class<K> keyType) : 根据键的class类型,通过反射的方式得到该枚举的所有可能值,进而生成一个键数组及值数组。

         public EnumMap(EnumMap<K, ? extends V> m) :从另一个EnumMap去初始化,本质上是生成一个副本。

         public EnumMap(Map<K, ? extends V> m):根据另一个Map初始化,和第二个方法相比,多了个对Map的转化的过程 

         以上三种初始化方式之后,在内部都会创建一个key数组和value数组,它们的大小是相同的。特别的,由于对同一类enum来说,其key是固定的,所以key数组是可以复用的。

         2. 存储

         我们来看一下对于put操作的实现     

    public V put(K key, V value) {
            typeCheck(key);//类型检查
    
            int index = key.ordinal();
            Object oldValue = vals[index];
            vals[index] = maskNull(value);//null值处理
            if (oldValue == null)
                size++;
            return unmaskNull(oldValue);
        }

          可以看到整个实现非常简单,key对应的value被存储在vals数组中,key的ordinal对应的下标的位置。

          需要注意的是,在存储时,系统对于值进行了maskNull的处理,在返回时做了unmaskNull处理,我们接着看下相关的代码:

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

           可以看到这个方法的作用是,如果目标value为null,则用NULL对象来替换,那么为什么要这样做呢?

           这是因为,vals数组中,默认是没有值的,而这个用null来表示。那么,EnumMap本身是支持值为null的,如果不做任何处理将vals设置为null,则无法和没有值的情况进行区分,所以借助于这种方式来实现对于null值的表示。

          3. 取值

          和存值一样,取值也是比较简单的,如下:

    public V get(Object key) {
            return (isValidKey(key) ?
                    unmaskNull(vals[((Enum)key).ordinal()]) : null);
        }

          可见相比较于HashMap,这个取值操作是直接定位的,非常快速。

          4. key存在判断

      前面说到,初始化时实际上就已经确定了key的数组,那么,是否表示所有的key都存在呢?参见实现:

    public boolean containsKey(Object key) {
            return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
        }

          可见,如果某个key对应的下标没有设置值,系统认为这个key是未被包含的。

    三、总结

         从前面的分析我们可以看到,EnumMap的实现非常简单,而且存取都非常高效,如果我们的业务场景是可以设置几个固定的key的值的话,那么用这类key将是非常高效的。

           

        

         

  • 相关阅读:
    并查集扩展域 —— [NOI2001]食物链
    C++ P4568 [JLOI2011]飞行路线 ---- Dijkstra+分层图
    单源最短路径--Dijkstra
    链式前向星学习
    深度理解链式前向星
    「学习笔记」链式前向星
    【转】到底EJB是什么
    什么是JPA
    把nc v6的源码看懂
    用友--扩展插件要怎么做
  • 原文地址:https://www.cnblogs.com/macs524/p/5827893.html
Copyright © 2011-2022 走看看