EnumMap源码分析

简介: <span style="font-family:微软雅黑; font-size:14px; line-height:21px; widows:auto">        自Java8以来,HashMap是高效的。应用HashMap完成枚举类型到值的映射也是我们常用的方式,但是EnumMap将更加高效。</span><span style="font-family:微软雅黑; font-s
        自Java8以来,HashMap是高效的。应用HashMap完成枚举类型到值的映射也是我们常用的方式,但是EnumMap将更加高效。 EnumMap顾名思义,是为枚举类服务的。
  • key必须为枚举类(Enum),且创建EnumMap时必须指定key的类型。
  • key不能为null,NullPointerException,但value允许null。
  • 底层结构均为数组,大小为Enum成员数量,创建EnumMap时会缓存所有枚举达到key数组。
  • 元素顺序为Enum的顺序,与put顺序无关。
  • 与HashMap类似,不保证线程安全。

注意:
  • 迭代时不会抛出ConcurrentModificationException。
  • NULL和null的区别。

1、重要属性
private  final  Class<K>  keyType;  // EnumMap的key的类型,在keyType中的enumConstants存放key的所有枚举值。
private transient K[] keyUniverse; //存放key的所有枚举值
private transient Object[] vals; // EnumMap的value值
private transient int size =0;

注意:key和value的底层机构均为数组
常用方法:
private Object maskNull(Object value) {
return (value == null ? NULL : value); //null变NULL,避免内部空指针异常
}
private V unmaskNull(Object value) {
return (V)(value == NULL ? null : value);
}
private static final Object NULL = new Object() {
public int hashCode() {
return 0;
}
public String toString() {
return "java.util.EnumMap.NULL";
}
};
2、put

public V put(K key, V value) {
typeCheck(key); // key必须是keyType类型或keyType子类型,否则ClassCastException异常
int index = key.ordinal(); // 以key的ordinal作为数组下标
Object oldValue = vals[index];
vals[index] = maskNull(value); //maskNull: value为空则返回自定义的空对象NULL
if (oldValue == null)
size++;
return unmaskNull(oldValue); 
//返回oldValue或null
}
3、get

public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
private boolean isValidKey(Object key) { // 检验key的有效性(不为null且类型合法)
if (key == null)
return false;
// Cheaper than instanceof Enum followed by getDeclaringClass
Class<?> keyClass = key.getClass();
return keyClass == keyType || keyClass.getSuperclass() == keyType;
}
    get方法先检验key的有效性,有效则以ordinal为下标返回vals[ordinal],否则返回null,So,和HashMap一样,不可以用get来判断EnumMap是否包含某一元素,因为某元素的value可能本就为null。
4、contains相关
public boolean containsKey(Object key) {
return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
注意containsKey和get的区别(仅仅未调用unmaskNull方法),以及EnumMap自定义的NULL和null的区别。
public boolean containsValue(Object value) {
value = maskNull(value); //null则返回NULL,否则返回value本身
for (Object val : vals) // 遍历vals
if (value.equals(val))
return true;
// 只要有一个相等即返回true
return false;
}
private boolean containsMapping(Object key, Object value) {
return isValidKey(key) &&
maskNull(value).equals(vals[((Enum<?>)key).ordinal()]);
}
// containsMapping方法是私有的,仅供EntrySet的contains方法调用。
5、遍历相关

// 遍历KeySet

Set keySet = enumMap.keySet();

terator iteKey = keySet.iterator();

while(iteKey.hasNext()){

    Object object =(Object) iteKey.next();

    System.out.print(object +"="+ enumMap.get(object)+"; ");

}

------------------

// 遍历values

Collection<Object> vals = enumMap.values();

Iterator iteVal = vals.iterator();

while(iteVal.hasNext()){

    Object object =(Object) iteVal.next();

    System.out.print(object +"; ");

    // ((Iterator) object).remove();// ClassCastException: String cannot be cast to Iterator

}

--------------------

// 遍历Entry

Set<Entry<Season, Object>> entrySet = enumMap.entrySet();

Iterator iteEn = entrySet.iterator();

while(iteEn.hasNext()){

    Entry object =(Entry) iteEn.next();

    System.out.print(object.getKey()+"; ");

    iteEn.remove();

}

注意: 和HashMap不同的是,EnumMap迭代不会抛ConcurrentModificationException异常。
for (Object entry : enumMap.entrySet()) {
            enumMap.remove(Season.summer); // 【--不抛-- ConcurrentModificationException 异常】
        }
        EnumMap中没有mouCount,相应Iterator中也没有expectedModCount,也就是说没有fast-fail机制。
相关分析参阅另一篇云笔记 HashMap迭代时不抛出ConcurrentModificationException的特例

6、其他方法

public voidclear(){

    Arrays.fill(vals,null);

    size =0;

}

public static void fill(Object[] a, Object val){

    for(int i =0, len = a.length; i < len; i++)

        a[i]= val; // 逐个遍历,好在vals[]元素也不会有太多

}

 

public V remove(Object key){

    if(!isValidKey(key))

        return null;

    int index =((Enum<?>)key).ordinal();

    Object oldValue = vals[index];

    vals[index]=null// 直接置null

    if(oldValue !=null)

        size--;

    return unmaskNull(oldValue); // 返回oldValue(包含null

}


相关资料:

目录
相关文章
|
1月前
|
存储 算法
HashMap源码分析
HashMap源码分析
|
8月前
|
存储 Java
HashMap 的 源码分析
HashMap 的 源码分析
60 0
|
10月前
|
存储 算法 Java
【Java集合框架 二】HashMap源码分析
【Java集合框架 二】HashMap源码分析
68 0
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
|
存储 安全 Java
java集合系列(3)ArrayList(源码分析)
这篇文章开始介绍ArrayList。ArrayList基本上是我们在平时的开发当中,使用最多的一个集合类了,它是一个其容量能够动态增长的动态数组。所以这篇文章,旨在从源码的角度进行分析和理解。为了使得文章更加有条理,还是先给出这篇文章的大致脉络: 首先,ArrayList的基本介绍和源码API(只给出方法分析,重要的方法给出详细代码)。 然后,介绍遍历ArrayList的几种方式 接下来,叙述一下ArrayList与其他集合关键字的区别和优缺点 最后,进行一个总结
214 0
java集合系列(3)ArrayList(源码分析)
|
存储 Java API
java集合系列(2)Collection(源码分析)
前一篇博客,我们基本上认识了集合,从这篇博客开始参考API文档,和源码分析,详细的介绍每个集合类的使用,力求在源码的角度来分析,加深理解。
123 0
java集合系列(2)Collection(源码分析)
HashSet源码解读
HashSet源码解读一:先看其实现了哪些接口和继承了哪些类 1.实现了Serializable接口,表明它支持序列化。 2.实现了Cloneable接口,表明它支持克隆,可以调用超类的clone()方法进行浅拷贝。
624 0
|
安全 Java 存储
java集合之ConcurrentSkipListSet源码分析——Set大汇总
java集合之ConcurrentSkipListSet源码分析——Set大汇总问题(1)ConcurrentSkipListSet的底层是ConcurrentSkipListMap吗? (2)ConcurrentSkipListSet是线程安全的吗? (3)ConcurrentSkipListSet是有序的吗? (4)ConcurrentSkipListSet和之前讲的Set有何不同? 简介ConcurrentSkipListSet底层是通过ConcurrentNavigableMap来实现的,它是一个有序的线程安全的集合。
1228 0
|
存储 安全 算法
Java集合:HashMap源码剖析
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/79936625 一、H...
835 0
|
安全 Java 索引
Java集合干货——ArrayList源码分析
ArrayList源码分析 前言 在之前的文章中我们提到过ArrayList,ArrayList可以说是每一个学java的人使用最多最熟练的集合了,但是知其然不知其所以然。关于ArrayList的具体实现,一些基本的都也知道,譬如数组实现,线程不安全等等,但是更加具体的就很少去了解了,例如:初始化的长度,扩容等。
1061 0