012_java.util.EnumMap

继承体系

image.png
EnumMap是Map体系中的一员,继承AbstractMap父类与Map接口,实现Enum接口。

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

查看其类声明定义,可以发现EnumMap的key要求必须是一个Enum类型。

重要变量

// key的Enum类型
private final Class<K> keyType;

// 所有k归纳为数组
private transient K[] keyUniverse;

// 所有value值归纳为数组
private transient Object[] vals;

// 当前存储的枚举量
private transient int size = 0;

由于EnumMap存储的是一个enum的数据,因此需要感知到Enum类型,在存储上由于Enum数据是确定的,可以使用确定的数组稳定存储。

构造函数

public EnumMap(Class<K> keyType) {
    this.keyType = keyType;
    keyUniverse = getKeyUniverse(keyType);
    vals = new Object[keyUniverse.length];
}

public EnumMap(EnumMap<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 EnumMap) {
        EnumMap<K, ? extends V> em = (EnumMap<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);
    }
}

private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
    return SharedSecrets.getJavaLangAccess()
                                    .getEnumConstantsShared(keyType);
}

EnumMap的构造器有三个,本质上最核心的就是求出枚举真实类型以及k数组与v数组。getKeyUniverse方法可以帮助我们从一个枚举获得其枚举原始类型。

重要方法

put方法

public V put(K key, V value) {
    // 检查key是否合法
    typeCheck(key);

    // 获得枚举序号
    int index = key.ordinal();
    
    // 从序号获得旧值
    Object oldValue = vals[index];

    // 如果为null则引用内部NULL对象作为该位置的值
    vals[index] = maskNull(value);

    // 如果旧值为空(初始化之后在该位置没有赋值),逻辑上size加一
    if (oldValue == null)
        size++;

    // 将旧值转换为真实值对外抛出
    return unmaskNull(oldValue);
}

private void typeCheck(K key) {
    Class<?> keyClass = key.getClass();
    // 传入key的类型不是当前目标存储的枚举类型的场合下将抛出异常
    if (keyClass != keyType && keyClass.getSuperclass() != keyType)
        throw new ClassCastException(keyClass + " != " + keyType);
}

private V unmaskNull(Object value) {
    return (V)(value == NULL ? null : value);
}

private Object maskNull(Object value) {
    return (value == null ? NULL : value);
}

put方法相比HashMap要简单的多,可以直接使用enum#ordinal来确定其在数组中的位置

get方法

public V get(Object key) {
    return (isValidKey(key) ?
            unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}

get方法将传入的key转换为enum然后获得其ordinal,进而在数据数组中获得对应的值

remove方法

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);
}

remove方法代码逻辑与get相似,都是先确定了传入key的位置,然后进行清理操作

总结

EnumMap存储了一个枚举的数据,其内部存在枚举真实类型的引用,与对应的枚举数组。由于枚举是确定的,因此枚举数组也是确定的。传入的枚举key对象可以通过其ordinal()序号来确定其数组的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值