EnumMap是一个用于存放键值为enum类型的map。全部的键值必须来自一个单一的enum类型。EnumMap内部用数组表示效率更高。

EnumMap维持键值的自然顺序(即枚举类型常量声明的顺序),能够通过keySet()entrySet()方法的集合视图来体现其顺序。

集合视图返回的迭代器是弱一致的:遍历时候不会抛出ConcurrentModificationException。遍历过程中若对容器进行改动。改动产生的影响遍历过程可能可见也可能不可见。

不同意null键值插入,插入空值将会抛出NullPointerException。測试空值是否存在或删除空值操作是同意的。

和其它集合对象实现类似,EnumMap不保证线程安全,能够通过集合帮助类的方法进行包装。返回线程安全的容器。

Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));

EnumMap实现

类的定义。能够看到键值必须是继承Enum<K>对象的实例

public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
implements java.io.Serializable, Cloneable

成员变量

private final Class<K> keyType; //key相应的class对象
// All of the values comprising K. (Cached for performance.)
private transient K[] keyUniverse;
//Array representation of this map.
private transient Object[] vals;
private transient int size = 0; //map的大小
//用非空值对象来表示null
private static final Object NULL = new Object();

构造方法

public EnumMap(Class<K> keyType) {
this.keyType = keyType;
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
}
/**
* Returns all of the values comprising K.
* The result is uncloned, cached, and shared by all callers.
* 调用sun.misc.SharedSecrets类中方法返回相应枚举类的成员
*/
private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(keyType);
}

put和remove方法

public V put(K key, V value) {
typeCheck(key);
int index = ((Enum)key).ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
//检查是否为初始化时传入的枚举类型或其子类型(? extends K)
private void typeCheck(K key) {
Class keyClass = key.getClass();
if (keyClass != keyType && keyClass.getSuperclass() != keyType)
throw new ClassCastException(keyClass + " != " + keyType);
}
private Object maskNull(Object value) {
return (value == null ? NULL : value);
}
private V unmaskNull(Object value) {
return (V) (value == NULL ? null : value);
}
public V remove(Object key) {
if (!isValidKey(key))
return null;
int index = ((Enum)key).ordinal();
Object oldValue = vals[index];
vals[index] = null;
if (oldValue != null)
size--;
return unmaskNull(oldValue);
}

get方法

public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum)key).ordinal()]) : null);
}
private boolean isValidKey(Object key) {
if (key == null)
return false;
// Cheaper than instanceof Enum followed by getDeclaringClass
Class keyClass = key.getClass();
return keyClass == keyType || keyClass.getSuperclass() == keyType;
}

查找方法

public boolean containsKey(Object key) {
return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
}
//即使是value为null,因为内部调用maskNull所以不会有空指针异常
private boolean containsMapping(Object key, Object value) {
return isValidKey(key) &&
maskNull(value).equals(vals[((Enum)key).ordinal()]);
}
public boolean containsValue(Object value) {
value = maskNull(value);
for (Object val : vals)
if (value.equals(val))
return true;
return false;
}

集合视图

HashMap类似,提供keySet()values()entrySet()方法。返回键集合、值集合、键值对集合视图。以下介绍下键集合视图,因为这些视图是无状态的,不是必需每次都又一次创建。ketSet方法返回一个内部类EnumMap$KeySet实例。

public Set<K> keySet() {
Set<K> ks = keySet;
if (ks != null)
return ks;
else
return keySet = new KeySet();
}
private class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return new KeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
int oldSize = size;
EnumMap.this.remove(o);
return size != oldSize;
}
public void clear() {
EnumMap.this.clear();
}
}

视图的迭代器

KeySet的迭代器返回内部类KeyIterator实例,其继承自EnumMapIterator,实际EnumMapIterator实现了整个Entry的迭代,依据不同视图。next方法返回键、值或键值对。

内部没有检查遍历过程是否改动,所以不会抛异常。

private class KeyIterator extends EnumMapIterator<K> {
public K next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedIndex = index++;
return keyUniverse[lastReturnedIndex];
}
} private class ValueIterator extends EnumMapIterator<V> {
public V next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedIndex = index++;
return unmaskNull(vals[lastReturnedIndex]);
}
} private abstract class EnumMapIterator<T> implements Iterator<T> {
// Lower bound on index of next element to return
int index = 0;
// Index of last returned element, or -1 if none
int lastReturnedIndex = -1; public boolean hasNext() {
while (index < vals.length && vals[index] == null)
index++;
return index != vals.length;
} public void remove() {
checkLastReturnedIndex();
if (vals[lastReturnedIndex] != null) {
vals[lastReturnedIndex] = null;
size--;
}
lastReturnedIndex = -1;
} private void checkLastReturnedIndex() {
if (lastReturnedIndex < 0)
throw new IllegalStateException();
}
}

总结

  1. EnumMap的键值必须是Enum类型。并且put的时候仅仅能是初始化时指定的Enum或者其子类型。同一时候不支持键值为null。
  2. EnumMap初始化会创建存放key和value的两个数组,大小为Enum类型中成员数量,同一时候会缓存全部Enum类型到key数组。
  3. EnumMap迭代保持键值的自然顺序(即枚举类型常量声明的顺序),事实上通过Enum内部ordinal()方法实现,vals数组每次插入元素都放插入到key值相应的ordinal()返回地点。

版权声明:本文博主原创文章,博客,未经同意不得转载。

EnumMap源代码阅读器的更多相关文章

  1. spring framework 4 源代码阅读器(1) --- 事前准备

    在你开始看代码.的第一件事要做的就是下载代码. 这里:https://github.com/spring-projects/spring-framework 下载完整的使用发现gradle建立管理工具 ...

  2. CopyOnWriteArrayList源代码阅读器

    java.util.concurrent在相应的并发集合的包中定义的通用集合类,为了有效地处理并发场景.间CopyOnWriteArrayList它是合适ArrayList.顾名思义CopyOnWri ...

  3. Silverlight类百度文库在线文档阅读器

    百度文库阅读器是基于Flash的,用Silverlight其实也可以做. 我实现的在线阅读器可以应用于内网文档发布,在线阅览审批等.没有过多的堆积功能,专注于核心功能.主要有以下特性: 1. 基于XP ...

  4. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

  5. 淘宝数据库OceanBase SQL编译器部分 源代码阅读--Schema模式

    淘宝数据库OceanBase SQL编译器部分 源代码阅读--Schema模式 什么是Database,什么是Schema,什么是Table,什么是列,什么是行,什么是User?我们能够能够把Data ...

  6. Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表

    在上一边博客<Web版RSS阅读器(一)——dom4j读取xml(opml)文件>中已经讲过如何读取rss订阅文件了.这次就把订阅的文件读取到页面上,使用树形结构进行加载显示. 不打算使用 ...

  7. Silverlight类百度文库在线文档阅读器(转)

    百度文库阅读器是基于Flash的,用Silverlight其实也可以做. 我实现的在线阅读器可以应用于内网文档发布,在线阅览审批等.没有过多的堆积功能,专注于核心功能.主要有以下特性: 1. 基于XP ...

  8. 【转】Tomcat源代码阅读系列

    在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码(Tomcat源代码阅读系列之一) Tomcat总体结构(Tomcat源代码阅读系列之二) Tomcat启动过程(Tomcat ...

  9. Adobe阅读器漏洞(adobe_cooltype_sing)学习研究

    实验环境:Kali 2.0+Windows XP sp3+Adobe Reader 9.0.0 类别:缓冲区溢出 描述:这个漏洞针对Adobe阅读器9.3.4之前的版本,一个名为SING表对象中一个名 ...

随机推荐

  1. 在C#调用C++的DLL方法(一)生成非托管dll

    C#与C/C++相比,前者的优势在于UI,后者的优势在于算法,C++下的指针虽然恶心,若使用得当还是相当方便的,最重要的问题是,市面上很多流行的开发工具库,几乎没有不支持C++的,但全面支持C#只能说 ...

  2. R与数据分析旧笔记(八)多重共线性

    多重共线性(线性代数叫线性相关) 多重共线性(线性代数叫线性相关) 1.什么是多重共线性 2.多重共线性对回归模型的影响 3.利用计算特征根发现多重共线性 4.Kappa()函数 例题1 考虑一个有六 ...

  3. jq 22 一个很好图片显示

    Picbox 示例页面:http://www.jq22.com/Demo961

  4. clip原理

    1.clip的概述: clip是修剪之意 clip有4个属性值:inherit auto rect(20px,40px,60px,0px) !important 其中有作用的仅rect这个属性值,着重 ...

  5. codeforces 633G. Yash And Trees dfs序+线段树+bitset

    题目链接 G. Yash And Trees time limit per test 4 seconds memory limit per test 512 megabytes input stand ...

  6. Linux ---> 监控JVM工具

    Linux ---> 监控JVM工具shkingshking 发布时间: 2013/10/10 01:27 阅读: 2642 收藏: 26 点赞: 1 评论: 0 JDK内置工具使用 jps(J ...

  7. WL(Wear leveling)磨损平衡

    前面说过,闪存寿命是以P/E次数来计算的,而WL就是确保闪存内每个块被写入的次数相等的一种机制.若没有这个机制,SSD内的闪存颗粒就无法在同一时间内挂掉,那对用户来说就是灾难.       会出现这种 ...

  8. android网络通讯数据封装之 json

    Demo程序包括客户端和服务端 客户端按json数据格式封装数据传至服务端. 服务端为简单的servlet程序,负责接收客户端传到json数据,然后按原数据返回客户端. 实例代码如下: public ...

  9. Android实现获取应用程序相关信息列表的方法

    本文所述为Androdi获取手机应用列表的方法,比如获取到Android应用的软件属性.大小和应用程序路径.应用名称等,获取所有已安装的Android应用列表,包括那些卸载了的,但没有清除数据的应用程 ...

  10. HDU 4436 str2int(后缀自动机)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4436 [题目大意] 给出一些字符串,由0~9组成,求出所有不同子串的和. [题解] 将所有字符串添 ...