java中的EnumSet

EnumSet

EnumSet是与枚举类型一起使用的专用Set集合,EnumSet的所有元素必须都是枚举类型。

内部实现是位向量,是一种高效的位运算操作。由于直接存储和操作都是bit,时间和空间性能都很可观。不允许使用null元素。线程不安全。

创建一个EnumSet不能使用new创建。因为是抽象类,使用提供的工厂方法创建。

创建一个具有指定元素类型的空EnumSetEnumSet<E>  noneOf(Class<E> elementType)       
//创建一个指定元素类型并包含所有枚举值的EnumSet
<E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
// 创建一个包括枚举值中指定范围元素的EnumSet
<E extends Enum<E>> EnumSet<E> range(E from, E to)
// 初始集合包括指定集合的补集
<E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s)
// 创建一个包括参数中所有元素的EnumSet
<E extends Enum<E>> EnumSet<E> of(E e)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
<E extends Enum<E>> EnumSet<E> of(E first, E... rest)
//创建一个包含参数容器中的所有元素的EnumSet
<E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)
<E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)

​ EnumSet内部使用位向量实现的。是一个抽象类存在两个子类,RegularEnumSet和JumbpEnumSet。RegularEnumSet使用一个long类型的变量作为位向量,long类型的位长度是64,因此可以存储64个枚举实例的标志位。JumboEnumSet使用一个long类型的数组,当枚举个数超过64时,就会采用long数组的方式存储。

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable
{
    //表示枚举类型
    final Class<E> elementType;
    //存储该类型信息所表示的所有可能的枚举实例
    final Enum<?>[] universe;
    //..........
}
  public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        //根据EnumMap中的一样,获取所有可能的枚举实例
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            //枚举个数小于64,创建RegularEnumSet
            return new RegularEnumSet<>(elementType, universe);
        else
            //否则创建JumboEnumSet
            return new JumboEnumSet<>(elementType, universe);
    }
实现类的构造函数
//RegularEnumSet构造
RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
      super(elementType, universe);
  }

//JumboEnumSet构造
JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
      super(elementType, universe);
      elements = new long[(universe.length + 63) >>> 6];
  }

在RegularEnumSet类和JumboEnumSet类中都存在一个elements变量,用于记录位向量的操作。

//RegularEnumSet
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
    private static final long serialVersionUID = 3411599620347842686L;
    //通过long类型的elements记录位向量的操作
    private long elements = 0L;
    //.......
}

//对于JumboEnumSet则是:
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
    private static final long serialVersionUID = 334349849919042784L;
    //通过long数组类型的elements记录位向量
    private long elements[];
     //表示集合大小
    private int size = 0;

    //.............
    }

add操作

public boolean add(E e) {
    //检测是否为枚举类型
    typeCheck(e);
    //记录旧elements
    long oldElements = elements;
    //执行位向量操作,是不是很熟悉?
    //数组版:a[i >> SHIFT ] |= (1 << (i & MASK))
    elements |= (1L << ((Enum)e).ordinal());
    return elements != oldElements;
}

remove操作

//RegularEnumSet类实现
public boolean remove(Object e) {
    if (e == null)
        return false;
    Class eClass = e.getClass();
    if (eClass != elementType && eClass.getSuperclass() != elementType)
        return false;

    long oldElements = elements;
    //将int型变量j的第k个比特位设置为0,即j= j&~(1<<k)
    //数组类型:a[i>>SHIFT] &= ~(1<<(i &MASK));

    elements &= ~(1L << ((Enum)e).ordinal());//long遍历类型操作
    return elements != oldElements;
}


//JumboEnumSet类的remove实现
public boolean remove(Object e) {
        if (e == null)
            return false;
        Class<?> eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false;
        int eOrdinal = ((Enum<?>)e).ordinal();
        int eWordNum = eOrdinal >>> 6;

        long oldElements = elements[eWordNum];
        //与a[i>>SHIFT] &= ~(1<<(i &MASK));相同
        elements[eWordNum] &= ~(1L << eOrdinal);
        boolean result = (elements[eWordNum] != oldElements);
        if (result)
            size--;
        return result;
    }

contain和containAll方法

public boolean contains(Object e) {
    if (e == null)
        return false;
    Class eClass = e.getClass();
    if (eClass != elementType && eClass.getSuperclass() != elementType)
        return false;
    //先左移再按&操作
    return (elements & (1L << ((Enum)e).ordinal())) != 0;
}

public boolean containsAll(Collection<?> c) {
    if (!(c instanceof RegularEnumSet))
        return super.containsAll(c);

    RegularEnumSet<?> es = (RegularEnumSet<?>)c;
    if (es.elementType != elementType)
        return es.isEmpty();
    //~elements取反相当于elements补集,再与es.elements进行&操作,如果为0,
    //就说明elements补集与es.elements没有交集,也就是es.elements是elements的子集
    return (es.elements & ~elements) == 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值