Java8 EnumMap / EnumSet 源码解析

  目录

一、EnumMap

1、定义

2、put / putAll / get

 3、remove / clear

二、EnumSet

1、定义

2、noneOf / allOf / of / range

3、copyOf / complementOf

三、RegularEnumSet

1、add / addAll / addRange / complement

2、 remove / removeAll / clear / retainAll

3、size / contains / containsAll / iterator

四、JumboEnumSet

1、add / addAll / addRange / complement

2、 remove / removeAll / clear / retainAll

3、size / contains / containsAll / iterator


EnumMap和EnumSet 都是为key类型为枚举的定制集合类,相比直接使用HashMap或者HashSet效率更高,更节省内存占用,本篇博客就详细探讨其实现细节。HashSet的实现是基于HashMap,HashMap的实现可以参考《java8 HashMap接口实现源码解析》。

一、EnumMap

1、定义

      EnumMap的类继承关系如下:

Java8 EnumMap / EnumSet 源码解析_第1张图片

其包含的属性如下:

    /**
     * K的类型
     */
    private final Class keyType;

    /**
     * 保存K值的数组,根据枚举类型来初始化,初始完成后不会改变,删除某个key时只删除对应的value,key值对应的数组元素不变
     */
    private transient K[] keyUniverse;

    /**
     * 保存V值的数组,与保存K值的数组是一一对应的,可以通过枚举值的索引即ordinal属性来访问,该属性从0开始
     */
    private transient Object[] vals;

    /**
     * Map的元素个数
     */
    private transient int size = 0;

    /**
     * 表示值为null的value
     */
    private static final Object NULL = new Object() {
        public int hashCode() {
            return 0;
        }

        public String toString() {
            return "java.util.EnumMap.NULL";
        }
    };

要求K必须扩展自Enum,即必须是枚举类型,参考EnumMap的定义,如下:

其构造方法的实现如下:

public EnumMap(Class keyType) {
        this.keyType = keyType;
        //根据枚举类型获取所有的枚举值
        keyUniverse = getKeyUniverse(keyType);
        //创建一个跟枚举值数组长度一样的value数组
        vals = new Object[keyUniverse.length];
    }

public EnumMap(EnumMap m) {
        //直接赋值
        keyType = m.keyType;
        keyUniverse = m.keyUniverse;
        vals = m.vals.clone();
        size = m.size;
    }

public EnumMap(Map m) {
        if (m instanceof EnumMap) {
            //直接赋值
            EnumMap em = (EnumMap) 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");
            //获取key值的类型    
            keyType = m.keySet().iterator().next().getDeclaringClass();
            //根据枚举类型获取所有的枚举值
            keyUniverse = getKeyUniverse(keyType);
            vals = new Object[keyUniverse.length];
            putAll(m);
        }
    }

//返回某个枚举类的所有枚举值,相当于调用对应枚举类的values方法
private static > K[] getKeyUniverse(Class keyType) {
        return SharedSecrets.getJavaLangAccess()
                                        .getEnumConstantsShared(keyType);
    }

2、put / putAll / get

 public V put(K key, V value) {
        //检查key的类型是否指定的枚举类型keyType
        typeCheck(key);
        //获取枚举值的索引
        int index = key.ordinal();
        //获取该索引对应的V
        Object oldValue = vals[index];
        //赋值
        vals[index] = maskNull(value);
        if (oldValue == null) //等于null,说明没有这个key值,size加1
            size++;
        return unmaskNull(oldValue); //返回原来的值
    }

 public void putAll(Map m) {
        if (m instanceof EnumMap) {
            //如果是EnumMap
            EnumMap em = (EnumMap)m;
            if (em.keyType != keyType) {
                if (em.isEmpty())
                    return;
                //key类型不一致,抛出异常    
                throw new ClassCastException(em.keyType + " != " + keyType);
            }
            //遍历所有的key值
            for (int i = 0; i < keyUniverse.length; i++) {
                //获取m中对应key的value
                Object emValue = em.vals[i];
                if (emValue != null) {
                    if (vals[i] == null) //等于null,说明没有这个key值,size加1
                        size++;
                    vals[i] = emValue; //赋值
                }
            }
        } else {
            //m是普通的HashMap,遍历键值对,调用put方法
            super.putAll(m);
        }
    }

public V get(Object key) {
        //如果是有效的key值,则获取对应key值的索引对应的value
        return (isValidKey(key) ?
                unmaskNull(vals[((Enum)key).ordinal()]) : null);
    }

private void typeCheck(K key) {
        Class keyClass = key.getClass();
        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
            throw new ClassCastException(keyClass + " != " + keyType);
    }

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

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

//是否有效key值
private boolean isValidKey(Object key) {
        if (key == null) //key不能为null
            return false;
        //判断key值的类型是否是keyType
        Class keyClass = key.getClass();
        return keyClass == keyType || keyClass.getSuperclass() == keyType;
    }

 3、remove / clear

public V remove(Object key) {
        if (!isValidKey(key)) //不是有效key,返回null
            return null;
        //获取key值索引对应的value    
        int index = ((Enum)key).ordinal();
        Object oldValue = vals[index];
        vals[index] = null; //置为null
        if (oldValue != null) //原来不为null,说明原来有这个key,则将size减1
            size--;
        return unmaskNull(oldValue);
    }

public void clear() {
        //将vals置为null,注意保存key值的数组keyUniverse没有变更
        Arrays.fill(vals, null);
        size = 0;
    }

二、EnumSet

1、定义

      EnumSet的类继承关系如下:

Java8 EnumMap / EnumSet 源码解析_第2张图片

注意EnumSet是一个抽象类,不能直接使用,该类有两个子类,如下:

Java8 EnumMap / EnumSet 源码解析_第3张图片

这两个子类都是非public的,只能包内访问。EnumSet.noneOf 方法创建EnumSet实例时会使用这两个子类,其实现如下:

Java8 EnumMap / EnumSet 源码解析_第4张图片

即枚举值的个数小于等于64时使用RegularEnumSet,大于64时使用JumboEnumSet。该类包含的属性如下:

    /**
     * 枚举的类型
     */
    final Class elementType;

    /**
     * 枚举类E的所有枚举值
     */
    final Enum[] universe;

 EnumSet定义了多个静态的工具类方法,其中核心方法如add的实现都留给了子类,下面逐一说明想法方法的实现。

2、noneOf / allOf / of / range

      这些方法都是用来创建EnumSet的,noneOf返回一个空的EnumSet,allOf返回一个包含指定枚举类所有枚举值的EnumSet,of方法返回一个包含一个或者多个的指定枚举值的EnumSet,range返回一个包含指定范围的枚举值的EnumSet。

//返回一个空的EnumSet
public static > EnumSet noneOf(Class elementType) {
        Enum[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }

//返回一个包含了所有枚举值的EnumSet
public static > EnumSet allOf(Class elementType) {
        EnumSet result = noneOf(elementType);
        //子类实现
        result.addAll();
        return result;
    }

//创建只包含一个指定枚举值的EnumSet,有多个重载版本,枚举值从1个到5个
public static > EnumSet of(E e) {
        EnumSet result = noneOf(e.getDeclaringClass());
        //子类实现
        result.add(e);
        return result;
    }

@SafeVarargs
public static > EnumSet of(E first, E... rest) {
        EnumSet result = noneOf(first.getDeclaringClass());
        result.add(first);
        //rest是不定数量的数组,将其中的元素都添加到Set中
        for (E e : rest)
            result.add(e);
        return result;
    }

//创建包含指定范围内的枚举值的EnumSet
public static > EnumSet range(E from, E to) {
        if (from.compareTo(to) > 0)
            throw new IllegalArgumentException(from + " > " + to);
        EnumSet result = noneOf(from.getDeclaringClass());
        //子类实现
        result.addRange(from, to);
        return result;
    }


//返回指定枚举类的所有枚举值
private static > E[] getUniverse(Class elementType) {
        return SharedSecrets.getJavaLangAccess()
                                        .getEnumConstantsShared(elementType);
    }

测试用例如下:

    enum Name{
        SHL,
        ABC,
        DEF,
        AVC,
        DNG
    }

    @Test
    public void test2() throws Exception {
        //返回一个空的EnumSet
        EnumSet names=EnumSet.noneOf(Name.class);
        System.out.println(names);
        //返回一个包含了所有枚举值的EnumSet
        names=EnumSet.allOf(Name.class);
        System.out.println(names);
        //返回一个包含了指定枚举值的EnumSet
        names=EnumSet.of(Name.ABC,Name.DEF);
        System.out.println(names);
        //返回一个包含了指定范围的枚举值的EnumSet,起始值都包含
        names=EnumSet.range(Name.ABC,Name.AVC);
        System.out.println(names);
    }
}

 输出如下:

Java8 EnumMap / EnumSet 源码解析_第5张图片

3、copyOf / complementOf

      copyOf用于复制指定的EnumSet,complementOf返回原EnumSet中不包含的枚举值。

public static > EnumSet copyOf(EnumSet s) {
        return s.clone();
    }

public static > EnumSet copyOf(Collection c) {
        if (c instanceof EnumSet) {
            //如果是EnumSet
            return ((EnumSet)c).clone();
        } else {
            if (c.isEmpty())
                throw new IllegalArgumentException("Collection is empty");
            //如果不是EnumSet,则遍历其中的元素,逐一添加到EnumSet中
            Iterator i = c.iterator();
            E first = i.next();
            EnumSet result = EnumSet.of(first);
            while (i.hasNext())
                result.add(i.next());
            return result;
        }
    }

//返回的EnumSet中包含了所有的枚举值
public static > EnumSet complementOf(EnumSet s) {
        EnumSet result = copyOf(s);
        //complement会补齐所有s中不包含的枚举值,由子类实现
        result.complement();
        return result;
    }

public EnumSet clone() {
        try {
            //调用Object的clone方法
            return (EnumSet) super.clone();
        } catch(CloneNotSupportedException e) {
            throw new AssertionError(e);
        }
    }

 测试用例如下:

   @Test
    public void test3() throws Exception {
        EnumSet names=EnumSet.allOf(Name.class);
        System.out.println(names);
        EnumSet names2=EnumSet.copyOf(names);
        System.out.println(names2);
        names.remove(Name.SHL);
        names2.remove(Name.DNG);
        System.out.println(names);
        System.out.println(names2);
        EnumSet names3=EnumSet.complementOf(names);
        System.out.println(names3);
    }

  其输出如下:

Java8 EnumMap / EnumSet 源码解析_第6张图片

三、RegularEnumSet

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

1、add / addAll / addRange / complement

 RegularEnumSet(ClasselementType, Enum[] universe) {
        super(elementType, universe);
    }

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

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

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

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

2、 remove / removeAll / clear / retainAll

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

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

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

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

3、size / contains / containsAll / iterator

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

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

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

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

private class EnumSetIterator> implements Iterator {
        /**
         * 当前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;
        }
    }

四、JumboEnumSet

       JumboEnumSet适用于枚举值个数大于64个的枚举类,其底层实现跟RegularEnumSet一样都是根据位是否为1来判断该枚举值是否添加到了Set中,不过因为枚举值个数大于64个,无法用64位的long类型来记录所有的枚举值,所以将RegularEnumSet中long类型的elements改成了一个long类型数组,添加某个枚举值时,先将某个枚举值的ordinal属性除以64,算出该枚举值所属的elements数组索引,再用ordinal属性对64求余,将对应的位标识位1,详情参考下面的源码分析。

1、add / addAll / addRange / complement

JumboEnumSet(ClasselementType, Enum[] universe) {
        super(elementType, universe);
        //加上63的目的是为了对64整除后算出来的值能包含原来的
        //以70为例,64整除的结果是1,1*64 小于原来的70,如果加上63,则整除的结果是2,大于原来的70
        elements = new long[(universe.length + 63) >>> 6];
    }

public boolean add(E e) {
        //检查e的枚举类型是否合法
        typeCheck(e);
        
        int eOrdinal = e.ordinal();
        //左移6位就是除以64,算出该枚举所属的elements数组索引
        int eWordNum = eOrdinal >>> 6;
        //获取原来的值
        long oldElements = elements[eWordNum];
        //eOrdinal的值是大于64的,此处右移,实际移动的位数是eOrdinal对64求余的结果
        //比如eOrdinal的值是68,1L<<68的结果就是1<<4,10000
        elements[eWordNum] |= (1L << eOrdinal);
        //判断原elements数组索引的元素是否发生改变,如果改变则说明添加的枚举值原来不存在
        boolean result = (elements[eWordNum] != oldElements);
        if (result) //为true说明添加了一个新元素,size加1
            size++;
        return result;
    }

void addAll() {
        //遍历所有的数组元素,将值置为-1,-1时所有位都是1
        for (int i = 0; i < elements.length; i++)
            elements[i] = -1;
        //最后一个数组元素不是所有位都是1的,只有universe.length对64求余的结果对应的位置为1,所以需要右移将其他的位置为0
        //以70为例,对64求余的结果就是6,-70的补码的后6位是111010,即58,64个1右移58后还剩6个1
        elements[elements.length - 1] >>>= -universe.length;
        size = universe.length;
    }

void addRange(E from, E to) {
        int fromIndex = from.ordinal() >>> 6;
        int toIndex = to.ordinal() >>> 6;
        
        //如果起始枚举值位于同一个数组元素中
        if (fromIndex == toIndex) {
            elements[fromIndex] = (-1L >>>  (from.ordinal() - to.ordinal() - 1))
                            << from.ordinal();
        } else {
            //起始枚举值不在同一个数组元素中
            //此处是左移,将低于from的位都置为0
            elements[fromIndex] = (-1L << from.ordinal());
            //将fromIndex + 1到toIndex-1之间的数组元素都置为-1,所有位变成1
            for (int i = fromIndex + 1; i < toIndex; i++)
                elements[i] = -1;
            //将to之前的低位都置为1    
            elements[toIndex] = -1L >>> (63 - to.ordinal());
        }
        //注意调用addRange时,JumboEnumSet是空的,所以此处直接赋值size
        size = to.ordinal() - from.ordinal() + 1;
    }

 void complement() {
        //遍历所有数组元素,取非,原来为0的位变成1,原来为1的位变成0
        for (int i = 0; i < elements.length; i++)
            elements[i] = ~elements[i];
        //处理最后一个数组元素,将多余的位都置为0    
        elements[elements.length - 1] &= (-1L >>> -universe.length);
        //总长度减去原来的长度
        size = universe.length - size;
    }

2、 remove / removeAll / clear / retainAll

public boolean remove(Object e) {
        if (e == null)
            return false;
        Class eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false; //元素类型不符,返回false
        //对64整除,算出所属的数组索引
        int eOrdinal = ((Enum)e).ordinal();
        int eWordNum = eOrdinal >>> 6;
        
        //将对应的数组元素的对应位置为0 
        long oldElements = elements[eWordNum];
        elements[eWordNum] &= ~(1L << eOrdinal);
        boolean result = (elements[eWordNum] != oldElements);
        if (result) //如果改变说明原来是有这个枚举值的,size减1
            size--;
        return result;
    }

public boolean removeAll(Collection c) {
        if (!(c instanceof JumboEnumSet))
            //调用父类removeAll,底层是遍历c,调用remove方法
            return super.removeAll(c);

        JumboEnumSet es = (JumboEnumSet)c;
        if (es.elementType != elementType)
            return false; //元素类型不符,返回false
         
        //遍历当前Set,先对es.elements[i]求非,将原来为1的位变成0,再和elements[i]求且,
        //实现将位于es.elements[i]中的元素都从elements[i]中移除了
        for (int i = 0; i < elements.length; i++)
            elements[i] &= ~es.elements[i];
        //重新计算size,返回size是否改变    
        return recalculateSize();
    }

public boolean retainAll(Collection c) {
        if (!(c instanceof JumboEnumSet))
            //调用父类retainAll,底层是遍历当前Set,如果不在c中则将其移除
            return super.retainAll(c);

        JumboEnumSet es = (JumboEnumSet)c;
        if (es.elementType != elementType) {
            //元素类型不一致,将当前Set清空
            boolean changed = (size != 0); 
            clear();
            return changed;
        }
        //遍历当前Set,两者的数组元素求且,不在es.elements[i]中的位就会被置为0,实现元素移除的效果
        for (int i = 0; i < elements.length; i++)
            elements[i] &= es.elements[i];
        //重新计算size,返回size是否改变    
        return recalculateSize();
    }

 public void clear() {
        //所有元素都置为0
        Arrays.fill(elements, 0);
        size = 0;
    }

//重新计算size,并返回size是否发生改变
private boolean recalculateSize() {
        int oldSize = size;
        size = 0;
        for (long elt : elements)
            //遍历elements,累加位为1的总数
            size += Long.bitCount(elt);
        //如果size发生改变,说明有删除元素了,返回true
        return size != oldSize;
    }

3、size / contains / containsAll / iterator

 public int size() {
        return size;
    }

 public boolean contains(Object e) {
        if (e == null)
            return false;
        Class eClass = e.getClass();
        if (eClass != elementType && eClass.getSuperclass() != elementType)
            return false; //枚举类型不符,返回false

        int eOrdinal = ((Enum)e).ordinal();
        //判断对应数组元素的对应位是否为0,如果是则说明不存在,返回false,否则返回true
        return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
    }

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

        JumboEnumSet es = (JumboEnumSet)c;
        if (es.elementType != elementType) //元素类型不符
            return es.isEmpty(); 

        for (int i = 0; i < elements.length; i++)
            //elements[i]先求非,原来为1的位变成0,再求且,如果结果不为0,说明某个元素在
            //elements[i]中不存在,在es.elements[i]中存在,即c中某个元素不在当前Set中,返回false
            if ((es.elements[i] & ~elements[i]) != 0)
                return false;
        return true;
    }

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

private class EnumSetIterator> implements Iterator {
        /**
         * 当前遍历的elements元素
         */
        long unseen;

        /**
         当前遍历的elements数组索引
         */
        int unseenIndex = 0;

        /**
         * 上一次返回的为1的位
         */
        long lastReturned = 0;

        /**
         * The index corresponding to lastReturned in the elements array.
         */
        int lastReturnedIndex = 0;

        EnumSetIterator() {
            unseen = elements[0];
        }

        @Override
        public boolean hasNext() {
            //遍历找到下一个数组元素不为0的数组元素
            while (unseen == 0 && unseenIndex < elements.length - 1)
                unseen = elements[++unseenIndex];
            return unseen != 0;
        }

        @Override
        @SuppressWarnings("unchecked")
        public E next() {
            if (!hasNext())
                throw new NoSuchElementException();
            //逻辑同RegularEnumSet    
            lastReturned = unseen & -unseen;
            lastReturnedIndex = unseenIndex;
            unseen -= lastReturned;
            return (E) universe[(lastReturnedIndex << 6)
                                + Long.numberOfTrailingZeros(lastReturned)];
        }

        @Override
        public void remove() {
            if (lastReturned == 0)
                throw new IllegalStateException();
            final long oldElements = elements[lastReturnedIndex];
            //对应的位置为0
            elements[lastReturnedIndex] &= ~lastReturned;
            if (oldElements != elements[lastReturnedIndex]) {
                size--;
            }
            lastReturned = 0;
        }
    }

 

 

 

 

 

 

 

 

你可能感兴趣的:(java8集合工具类源码解析,EnumMap,EnumSet,RegularEnumSet,JumboEnumSet)