EnumMap的用法和源码解析

EnumMap的用法

   EnumMap顾名思义是保存枚举类型的Map.它要求map的key是枚举类型。这点在类定义的时候就已经声明好了EnumMap<K extends Enum<K>, V>,如何不是枚举类型编译会出错。

 eg:定义了一个Enum类 JdbcType。

   public enum JdbcType {
        INT,NUMBER,VARCHAR,VARCHAR2,LONG,BLOB,CHAR;
   }

--------------------------------------------EnumMap的一个简单应用-----------------------------------------------

public class EnumMapTest {

public static void main(String[] args) {
     EnumMap<JdbcType, String> enumMap=new EnumMap<JdbcType, String>(JdbcType.class);
     enumMap.put(JdbcType.INT, "INT TYPE");
     enumMap.put(JdbcType.NUMBER, "NUMBER TYPE");
     enumMap.put(null,"NULL ");
     System.out.println(enumMap.get(JdbcType.INT));
}
}

    EnumMap的有什么优点,为什么我们要用EnumMap。

          .1 相比HashMap,EnumMap的性能和速度要快的多。EnumMap里面的数据结构是数组,获取的数据的时候特别快。而且添加的数据的时候(一般用put(K,V)),这里面的并不像一般数组一样,当插入到中间的位置时候,要数组整体移动(一般实现依次向后移动)。EnumMap实现不需要,因为数组在EnumMap实例化的时候就已经初始化好了,要做的就是对原来的oldValue进行覆盖,这样无论获取数据还是添加和删除数据都要快的多。这里特别提示一下,为什么EnumMap能够用数组,这得益于EnumMap的key是枚举类型,枚举类类型中每一种类型,在声明的时候都有确定的位置,可以通过对应的位置确定的枚举类型。通过该方法获得位置key.ordinal();

          2.枚举类型的相应的类型更加明确,key对应的范围更加明确。列如的key是string,那么你的键范围无法确定。所以能够用EnumMap,尽量用EnumMap这也是一种代码优化方案’

     EnumMap的大量用到各种框架中,在Mabatis的TypeHandlerRegistry中就用到了EnumMap:
  

     public final class TypeHandlerRegistry {

     private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);

     有兴趣的同学可以去看看TypeHandlerRegistry源码,会对EnumMap理解更加透彻。

  下面对EnumMap源码进行解析:

                                         

              public EnumMap(Class<K> keyType) {   //EnumMap的构造器  keyType是key的类型,只能是枚举类型,否则不能编译过去
                 this.keyType = keyType; 
                 keyUniverse = getKeyUniverse(keyType);//getKeyUniverse方面获得该枚举中所有类型,返回一个数组该枚举类型中所有实例

                 vals = new Object[keyUniverse.length];//初始化该数组,该数组大小不会改变,因为枚举类型确定了,相同的键会进行值的覆盖,该数组也是map底层的数据结构

             }


        新增方法:

public V put(K key, V value) {
typeCheck(key); //类型检查,只有该enum类型才能,进行数据录入。实际开发中null值可以编译通过,但是到这步检查会报空指针。

int index = key.ordinal();//获取改值在enum中的声明的位置,通过该位置定位该值
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null) //oldNull为null为新增,oldNull有值进行覆盖
size++;
return unmaskNull(oldValue);
}

该方法 的用法API说的很清楚了:

   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.


            删除方法:

                      public V remove(Object key) {

if (!isValidKey(key)) // 如何该key是null,或者不是初始化时enum类型,直接返回null,不进行删除操作
return null;
int index = ((Enum<?>)key).ordinal(); //获取该值的位置,也是在数组中位置
Object oldValue = vals[index]; //定位该值
vals[index] = null; //对该值赋值null,也就是常见的逻辑删除,故删除速度也很快,不进行数组移动,定位之后,进行赋值操作
if (oldValue != null) //原来有值对数组大小进行-1操作,否则不操作。
size--;
return unmaskNull(oldValue);
}


               get值方法:该方法很简单不做解释:

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

 

 EnumMap源码就解析到这里了,感兴趣的同学可以自己看看。

猜你喜欢

转载自www.cnblogs.com/caibixiang123/p/9214086.html