EnumMap源码阅读
来源:互联网 发布:java执行ping命令 编辑:程序博客网 时间:2024/04/29 11:12
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的大小//用非空值对象来表示nullprivate 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(); }}
总结
EnumMap
的键值必须是Enum类型,而且put的时候只能是初始化时指定的Enum或者其子类型。同时不支持键值为null。EnumMap
初始化会创建存放key和value的两个数组,大小为Enum类型中成员数量,同时会缓存所有Enum类型到key数组。EnumMap
迭代保持键值的自然顺序(即枚举类型常量声明的顺序),其实通过Enum内部ordinal()
方法实现,vals数组每次插入元素都放插入到key值对应的ordinal()
返回的位置。
1 0
- EnumMap源码阅读
- EnumMap源码分析
- EnumMap类源码解析
- jdk源码剖析之EnumMap
- EnumMap
- EnumMap
- EnumMap
- EnumMap
- java-EnumMap、IdentityHashMap、WeakHashMap源码分析
- 阅读源码
- 阅读源码
- 阅读源码
- 源码阅读
- EnumMap学习
- java enumMap
- EnumMap示例
- JAVA EnumMap
- EnumMap学习
- [toj 1144] Tree Recovery
- Linux strace命令
- JAVA序列化基础知识Serializable与Externalizable的区别
- java面试题收集
- Python --- Bottle: 轻量级Web Server
- EnumMap源码阅读
- VMware Workstation 集群仲裁磁盘和数据共享磁盘的创建
- tomcat下禁用不安全的http方法
- WebKit绘制
- 校园助手APP--WebView显示校园贴吧
- JavaBean简介
- 设计模式三部曲--4
- Python标准库:内置函数dict(mapping, **kwarg)
- 在访问者模式中使用反射