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的類繼承關係如下:

其包含的屬性如下:

    /**
     * K的類型
     */
    private final Class<K> 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<K> keyType) {
        this.keyType = keyType;
        //根據枚舉類型獲取所有的枚舉值
        keyUniverse = getKeyUniverse(keyType);
        //創建一個跟枚舉值數組長度一樣的value數組
        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");
            //獲取key值的類型    
            keyType = m.keySet().iterator().next().getDeclaringClass();
            //根據枚舉類型獲取所有的枚舉值
            keyUniverse = getKeyUniverse(keyType);
            vals = new Object[keyUniverse.length];
            putAll(m);
        }
    }

//返回某個枚舉類的所有枚舉值,相當於調用對應枚舉類的values方法
private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> 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<? extends K, ? extends V> 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的類繼承關係如下:

注意EnumSet是一個抽象類,不能直接使用,該類有兩個子類,如下:

這兩個子類都是非public的,只能包內訪問。EnumSet.noneOf 方法創建EnumSet實例時會使用這兩個子類,其實現如下:

即枚舉值的個數小於等於64時使用RegularEnumSet,大於64時使用JumboEnumSet。該類包含的屬性如下:

    /**
     * 枚舉的類型
     */
    final Class<E> elementType;

    /**
     * 枚舉類E的所有枚舉值
     */
    final Enum<?>[] universe;

 EnumSet定義了多個靜態的工具類方法,其中核心方法如add的實現都留給了子類,下面逐一說明想法方法的實現。

2、noneOf / allOf / of / range

      這些方法都是用來創建EnumSet的,noneOf返回一個空的EnumSet,allOf返回一個包含指定枚舉類所有枚舉值的EnumSet,of方法返回一個包含一個或者多個的指定枚舉值的EnumSet,range返回一個包含指定範圍的枚舉值的EnumSet。

//返回一個空的EnumSet
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> 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 <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
        EnumSet<E> result = noneOf(elementType);
        //子類實現
        result.addAll();
        return result;
    }

//創建只包含一個指定枚舉值的EnumSet,有多個重載版本,枚舉值從1個到5個
public static <E extends Enum<E>> EnumSet<E> of(E e) {
        EnumSet<E> result = noneOf(e.getDeclaringClass());
        //子類實現
        result.add(e);
        return result;
    }

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

//創建包含指定範圍內的枚舉值的EnumSet
public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
        if (from.compareTo(to) > 0)
            throw new IllegalArgumentException(from + " > " + to);
        EnumSet<E> result = noneOf(from.getDeclaringClass());
        //子類實現
        result.addRange(from, to);
        return result;
    }


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

測試用例如下:

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

    @Test
    public void test2() throws Exception {
        //返回一個空的EnumSet
        EnumSet<Name> 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);
    }
}

 輸出如下:

3、copyOf / complementOf

      copyOf用於複製指定的EnumSet,complementOf返回原EnumSet中不包含的枚舉值。

public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
        return s.clone();
    }

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

//返回的EnumSet中包含了所有的枚舉值
public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
        EnumSet<E> result = copyOf(s);
        //complement會補齊所有s中不包含的枚舉值,由子類實現
        result.complement();
        return result;
    }

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

 測試用例如下:

   @Test
    public void test3() throws Exception {
        EnumSet<Name> names=EnumSet.allOf(Name.class);
        System.out.println(names);
        EnumSet<Name> 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<Name> names3=EnumSet.complementOf(names);
        System.out.println(names3);
    }

  其輸出如下:

三、RegularEnumSet

     RegularEnumSet適用於枚舉值個數小於等於64的EnumSet,RegularEnumSet定義了一個私有的long類型變量elements,long類型一共64位,如果某一位爲1則表示該位對應的值對應的枚舉值已經添加到RegularEnumSet中了,具體細節參考下面的源碼分析。

1、add / addAll / addRange / complement

 RegularEnumSet(Class<E>elementType, 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<? 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;
    }

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

四、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(Class<E>elementType, 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<E> iterator() {
        return new EnumSetIterator<>();
    }

private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
        /**
         * 當前遍歷的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;
        }
    }

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章