《java集合》–EnumMap
说明:此文章基于jdk1.8
参考:
简介
首先对比HashMap的实现,HashMap数据结构是数组散列,key值做hash运算后根据算法落在数组上,不同的hash值最后可能落在同一个桶上,在一个桶上的多个entry对象使用链表存储,当数组没有链表存在时,HashMap性能最好为O(1)。而最差为O(threshould)即所有元素存在一个链表上
当枚举作为key存入map的情况,由于枚举值得个数是一定得,那么直接创建一个枚举值个数大小的数组用于存储,Enum性能为O(1)
所有的枚举类都继承自java.lang.Enum,根据ordinal()方法获取枚举实例的序号,然后去values数组中操作该下标处的value。
数据结构
EnumMap的存储结构是一个数组,数组中存储了value值,长度等于枚举实例的个数,根据枚举实例在枚举类中的ordinal去操作数组对应下标的value值
基本属性
- private final Class keyType;// 枚举类型
- private transient K[] keyUniverse; //枚举类型的values
- private transient Object[] vals; //EnumMap中存放的value值
构造器
创建EnumMap时传入Enum枚举的具体类型,EnumMap会根据枚举的values的size创建一个size大小的数组
public EnumMap(Class<K> keyType) {
this.keyType = keyType;
//获取枚举类型的所有value
keyUniverse = getKeyUniverse(keyType);
//根据values的size创建数组
vals = new Object[keyUniverse.length];
}
public EnumMap(EnumMap1<K, ? extends V> m) {
keyType = m.keyType;
keyUniverse = m.keyUniverse;
vals = m.vals.clone();
size = m.size;
}
public EnumMap(Map<K, ? extends V> m) {
if (m instanceof EnumMap1) {
EnumMap1<K, ? extends V> em = (EnumMap1<K, ? extends V>) m;
keyType = em.keyType;
keyUniverse = em.keyUniverse;
vals = em.vals.clone();
size = em.size;
} else {
if (m.isEmpty())
throw new IllegalArgumentException("Specified map is empty");
keyType = m.keySet().iterator().next().getDeclaringClass();
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
putAll(m);
}
}
添加元素
根据key值获取枚举的ordinal下标,直接向数组位置添加value
public V put(K key, V value) {
//验证枚举类型是否合法
typeCheck(key);
//获取枚举值在枚举类中的下标
int index = key.ordinal();
//从数组中获取对应下标的值
Object oldValue = vals[index];
//数组下标处赋值
vals[index] = maskNull(value);
//如果第一次加入 size+1
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
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);
}
//put的时候直接根据key获取ordinal,然后修改数组该下标处的值
public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
删除元素
获取到key值得下标,然后操作数组处指向null
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);
}
public void clear() {
Arrays.fill(vals, null);
size = 0;
}
获取元素
直接根据枚举值在枚举中的下标从value数组中获取,ordinal
public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
//验证key值是否合法
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;
}
遍历
只需要遍历数组,O(n)级别
//遍历value
public boolean containsValue(Object value) {
value = maskNull(value);
for (Object val : vals)
if (value.equals(val))
return true;
return false;
}
//遍历key
public boolean containsKey(Object key) {
return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
//迭代器
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();
}
}
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 class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
private Entry lastReturnedEntry;
public Map.Entry<K,V> next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedEntry = new Entry(index++);
return lastReturnedEntry;
}
public void remove() {
lastReturnedIndex =
((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
super.remove();
lastReturnedEntry.index = lastReturnedIndex;
lastReturnedEntry = null;
}
private class Entry implements Map.Entry<K,V> {
private int index;
private Entry(int index) {
this.index = index;
}
public K getKey() {
checkIndexForEntryUse();
return keyUniverse[index];
}
public V getValue() {
checkIndexForEntryUse();
return unmaskNull(vals[index]);
}
public V setValue(V value) {
checkIndexForEntryUse();
V oldValue = unmaskNull(vals[index]);
vals[index] = maskNull(value);
return oldValue;
}
public boolean equals(Object o) {
if (index < 0)
return o == this;
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
V ourValue = unmaskNull(vals[index]);
Object hisValue = e.getValue();
return (e.getKey() == keyUniverse[index] &&
(ourValue == hisValue ||
(ourValue != null && ourValue.equals(hisValue))));
}
public int hashCode() {
if (index < 0)
return super.hashCode();
return entryHashCode(index);
}
public String toString() {
if (index < 0)
return super.toString();
return keyUniverse[index] + "="
+ unmaskNull(vals[index]);
}
private void checkIndexForEntryUse() {
if (index < 0)
throw new IllegalStateException("Entry was removed");
}
}
}
总结
- 当key值是枚举类型的时候,使用EnumMap存储,会提高性能