先看看EnumMap的构造方法之一:
//类型
private final Class<K> keyType;
//所有key值的数组
private transient K[] keyUniverse;
//key对应的value值,长度固定为枚举个数
private transient Object[] vals;
public EnumMap(Class<K> keyType) {
//把类型参数赋值给keyType
this.keyType = keyType;
//这段代码底层用到了values的方法,把枚举类的key值都全部取出来,放到keyUniverse数组里
keyUniverse = getKeyUniverse(keyType);
//构造长度为keyUniverse数组长度的vals数组,用来存放值
vals = new Object[keyUniverse.length];
}
EnumMap的put方法:
public V put(K key, V value) {
//检查key的类型是不是对的,不符合则抛出异常
typeCheck(key);
//拿下标,对应的就是枚举成员在枚举中的顺序位置
int index = key.ordinal();
//先取得这个下标原来的值
Object oldValue = vals[index];
//做一个对于null值的特殊处理
vals[index] = maskNull(value);
//如果原来下标是null,现在赋值上去了,size就会加1,size代表这数组里的实际元素有多少
if (oldValue == null)
size++;
//对NULL对象做处理,返回
return unmaskNull(oldValue);
}
//为了判断value到底是不是null,如果真是null就赋值为NULL对象
private Object maskNull(Object value) {
return (value == null ? NULL : value);
}
//返回的时候用,如果真是NULL,那么就给它再转回成null做返回值
private V unmaskNull(Object value) {
return (V)(value == NULL ? null : value);
}
//NULL其实就是个重写了hashCode方法和toString方法的Object类
private static final Object NULL = new Object() {
public int hashCode() {
return 0;
}
public String toString() {
return "java.util.EnumMap.NULL";
}
};
EnumMap的get方法:
public V get(Object key) {
//先校验key是否合法,合法则直接通过key对应的下标在vals数组里取值,不然就返回null
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
总结
通过以上方法可以看出,EnumMap有两个数组属性很关键,一个 K[ ] keyUniverse数组用来初始化时放入枚举的所有key值,一个Object[] vals数组用来存放value值,他们是通过下标来一一对应的,因为put的时候会先取key的下标,来作为Object[] vals数组的下标,然后赋值,get时就能够直接通过key的下标在Object[] vals数组里找到对应的value值。当然了,用来作为类型检查的Class keyType 属性也是很关键的,他决定了这个EnumMap究竟能操作哪个枚举,要是不对应,就会抛出异常。