Java容器之RegularEnumSet源码分析

一、概述

RegularEnumSet适用于枚举值个数小于等于64EnumSetRegularEnumSet定义了一个私有的long类型变量elementslong类型一共64位,如果某一位为1则表示该位对应的值对应的枚举值已经添加到RegularEnumSet中了,具体细节参考下面的源码分析。

二、源码分析

2.1 构造方法

RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
    super(elementType, universe);
}

2.2 添加元素

2.2.1 add

public boolean add(E e) {
    //检查e的枚举类型是否指定的类型
    typeCheck(e);
    //获取原来的elements值
    long oldElements = elements;
    //将ordinal对应的位标识为1,表示添加了对应元素
    elements |= (1L << ((Enum<?>)e).ordinal());
    //如果不等说明原来不存在e,返回true
    return elements != oldElements;
}

2.2.2 addAll

void addAll() {
    if (universe.length != 0) //将所有枚举值对应的位都标识为1
        //-1实际就是64个1,注意此处是右移一个负值,实际是右移该负值的补码的后6位对应的位数,因为超过6位就大于64了
        //以universe.length为8为例,-8的补码的后6位是111000,该值为56,64个1右移56位的结果就是8个1
        elements = -1L >>> -universe.length;
}
 
public boolean addAll(Collection<? extends E> c) {
    if (!(c instanceof RegularEnumSet))
        //如果不是RegularEnumSet类型,则通过父类的addAll方法添加,底层是遍历c中的元素,循环调用add方法
        return super.addAll(c);

    //如果是RegularEnumSet类型
    RegularEnumSet<?> es = (RegularEnumSet<?>)c;
    if (es.elementType != elementType) {
        if (es.isEmpty())
            return false;
        else
            //枚举类型不符,抛出异常
            throw new ClassCastException(
                es.elementType + " != " + elementType);
    }
    
    long oldElements = elements;
    //直接或运算,有一个为1则结果为1
    elements |= es.elements;
    //两者不等说明有添加新的元素了
    return elements != oldElements;
}

2.2.3 addRange

void addRange(E from, E to) {
    //将指定范围内的位标记为1,
    //注意此处from.ordinal() - to.ordinal()是一个负值,再减1是为了将to也包含进来
    elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
}

2.2.4 complement

void complement() {
    if (universe.length != 0) {
        //取非,原来为1的变成0了,原来为0的变成1了
        elements = ~elements;
        //将universe范围以外的1都置为0
        elements &= -1L >>> -universe.length;  // Mask unused bits
    }
}

2.3 移除元素

2.3.1 remove

public boolean remove(Object e) {
    if (e == null)
        return false;
    Class<?> eClass = e.getClass();
    //不是指定枚举类,返回false
    if (eClass != elementType && eClass.getSuperclass() != elementType)
        return false;

    long oldElements = elements;
    //将ordinal对应的位置为0
    elements &= ~(1L << ((Enum<?>)e).ordinal());
    //如果不等于说明该元素原来是存在的,返回true
    return elements != oldElements;
}

2.3.2 removeAll

public boolean removeAll(Collection<?> c) {
    if (!(c instanceof RegularEnumSet))
        //调用父类removeAll,底层遍历c,循环调用remove方法
        return super.removeAll(c);

    RegularEnumSet<?> es = (RegularEnumSet<?>)c;
    if (es.elementType != elementType)
        return false; //枚举类型不符

    long oldElements = elements;
    //先对es.elements求非,原来的1变成0,再求且,就会将elements中同样是1的位置为0了
    elements &= ~es.elements;
    //如果不等于说明有元素被删除了
    return elements != oldElements;
}

2.3.3 clear

public void clear() {
    //置为0,所有为1的位都置为0了
    elements = 0;
}

2.3.4 retainAll

retainAll求两者的交集,将不在c中的元素移除,返回true表示有元素被移除了。

public boolean retainAll(Collection<?> c) {
    if (!(c instanceof RegularEnumSet))
        //调用父类retainAll,遍历当前集合Set,如果不在c中则移除
        return super.retainAll(c);

    RegularEnumSet<?> es = (RegularEnumSet<?>)c;
    if (es.elementType != elementType) {
        //枚举类型不符,将当前元素全部清空
        //不等于0说明原来的RegularEnumSet非空,此处清除了,发生修改了,返回true
        boolean changed = (elements != 0);
        elements = 0;
        return changed;
    }
    //枚举类型一致
    long oldElements = elements;
    //两者求且,如果某个元素在elements存在而在es.elements中不存在则将elements中对应位置为0,实现删除的效果
    elements &= es.elements;
    return elements != oldElements;
}

2.4 size

public int size() {
    //统计位为1的位的总数,比如bitCount(8)返回1,bitCount(3)返回2
    return Long.bitCount(elements);
}

2.5 包含

2.5.1 contains

public boolean contains(Object e) {
    if (e == null)
        return false;
    Class<?> eClass = e.getClass();
    if (eClass != elementType && eClass.getSuperclass() != elementType)
        return false; //枚举类型不符,返回false
    //判断ordinal对应的位是否为0,为0表示不存在
    return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
}

2.5.2 containsAll

public boolean containsAll(Collection<?> c) {
    if (!(c instanceof RegularEnumSet))
        //调用父类的containsAll,遍历c中的元素,如果有一个在当前Set中不存在则返回false
        return super.containsAll(c);

    RegularEnumSet<?> es = (RegularEnumSet<?>)c;
    if (es.elementType != elementType) //枚举类型不符,如果c是空的则返回true
        return es.isEmpty();
    
    //elements求反后跟es.elements求且,如果结果为0,说明c中的元素都在当前Set中,返回true
    return (es.elements & ~elements) == 0;
}

2.6 迭代器

public Iterator<E> iterator() {
    return new EnumSetIterator<>();
}

private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
    /**
     * 当前elements
     */
    long unseen;

    /**
     * 上一次返回的枚举值对应位为1的值,比如上一次返回的枚举值的ordinal为4,则lastReturned的后8位为00010000
     */
    long lastReturned = 0;

    EnumSetIterator() {
        unseen = elements;
    }

    public boolean hasNext() {
        return unseen != 0;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        if (unseen == 0)
            throw new NoSuchElementException();
        //unseen是奇数时,求且为1,是偶数时,求且是一个2的整数次幂    
        lastReturned = unseen & -unseen;
        //遍历一个位对应的枚举值,就通过减法,将对应位置为0
        unseen -= lastReturned;
        return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
    }

    public void remove() {
        if (lastReturned == 0)
            throw new IllegalStateException();
        //将对应的位置为0    
        elements &= ~lastReturned;
        lastReturned = 0;
    }
}
posted @ 2022-06-02 22:37  夏尔_717  阅读(80)  评论(0编辑  收藏  举报