来源:
Java编程的逻辑
如果需要一个Map的实现类,并且键的类型为枚举类型,可以使用HashMap,但应该使用一个专门的实现类EnumMap
因为枚举类型有两个特征,一是它可能的值是有限的且预先定义的,二是枚举值都有一个顺序,这两个特征使得可以更为高效的实现Map接口
EnumMap是保证顺序的,输出按照键在枚举中的顺序
内部基于数组实现
1 实现原理
1.1 内部组成
private final Class<K> keyType;//类型信息
private transient K[] keyUniverse;//表示键,是所有可能的枚举值
private transient Object[] vals;//键对应的值
private transient int size = 0;//键值对个数
1.2 构造方法
//基本构造方法
public EnumMap(Class<K> keyType) {
this.keyType = keyType;
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
}
//初始化键数组
//最终调用了枚举类型的values方法,values方法返回所有可能的枚举值
private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
return SharedSecrets.getJavaLangAccess().getEnumConstantsShared(keyType);
}
1.3 保存键值对
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);
}
private void typeCheck(K key) {
Class<?> keyClass = key.getClass();
if (keyClass != keyType && keyClass.getSuperclass() != keyType)
throw new ClassCastException(keyClass + " != " + keyType);
}
EnumMap允许值为null,为了区别null值与没有值,EnumMap将null值包装成了一个特殊的对象,有两个辅助方法用于null的打包和解包,打包方法为maskNull,解包方法为unmaskNull;
这个特殊对象及两个方法的代码为:
private static final Object NULL = new Object() {//null值
public int hashCode() {
return 0;
}
public String toString() {
return "java.util.EnumMap.NULL";
}
};
private Object maskNull(Object value) {
return (value == null ? NULL : value);
}
private V unmaskNull(Object value) {
return (V) (value == NULL ? null : value);
}
1.4 根据键获取值
public V get(Object key) {
return (isValidKey(key) ? unmaskNull(vals[((Enum)key).ordinal()]) : null);
}
//与typeCheck类似,但是返回boolean值而不是抛出异常
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;
}
1.5 查看是否包含某个值
//遍历值数组进行比较
public boolean containsValue(Object value) {
value = maskNull(value);
for (Object val : vals)
if (value.equals(val))
return true;
return false;
}
1.6 根据键删除
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);
}