EnumMap源码解析

来源:
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);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值