Java之EnumSet源碼分析

EnumSet:

1.定義:

  • 添加枚舉類元素的專用集合類

2.與其他集合類區別:

  • EnumSet內部實現不使用常見的數據結構,比如數組(ArrayList),鏈表(LinkedList),哈系表(HashMap、Hashtable、HashSet),紅黑樹(TreeMap、TreeSet)而是使用位運算完成集合的基本操作
  • EnumSet是抽象類,只能通過靜態工廠方法構造EnumSet對象,具體如下:
    EnumSet<E> noneOf(Class<E> elementType):構造一個空的集合
    EnumSet<E> allOf(Class<E> elementType):構造一個包含枚舉類中所有枚舉項的集合
    EnumSet<E> of(E e):構造包含1個元素的集合
    EnumSet<E> of(E e1, E e2):構造包含2個元素的集合
    EnumSet<E> of(E e1, E e2, E e3):構造包含3個元素的集合
    EnumSet<E> of(E e1, E e2, E e3, E e4):構造包含4個元素的集合
    EnumSet<E> of(E e1, E e2, E e3, E e4, E e5):構造包含5個元素的集合
    EnumSet<E> of(E first, E... rest):構造包含多個元素的集合(使用可變參數)
    EnumSet<E> copyOf(EnumSet<E> s):構造包含參數中所有元素的集合
    EnumSet<E> copyOf(Collection<E> c):構造包含參數中所有元素的集合

3.EnumSet作爲集合類基本操作方法實現原理(位運算):

說明

  • 從EnumSet的noneOf可以看出,當枚舉類中的枚舉項少於64時,返回的是RegularEnumSet類EnumSet的實現類)對象,大於64,返回的是JumboEnumSet類對象,爲了方便分析,後面同一使用RegularEnumSet類解釋原理
    // EnumSet#noneOf
    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);
    }
    
  • 測試用的枚舉類
    enum Color{
        RED("RED"),
        BLUE("BLUE"),
        YELLOW("YELLOW"),
        BLACK("BLACK");
    
        String name;
    
        Color(String name){
            this.name = name;
        }
    
        @Override
        public String toString(){
            return this.name;
        }
    }
    

3.1 add方法
public boolean add(E e) {
    typeCheck(e);
    long oldElements = elements;
    elements |= (1L << ((Enum<?>)e).ordinal());
    return elements != oldElements;
}

ordinal()爲每個枚舉項的序號,從0開始,按聲明順序排列,如[RED,BLUE,YELLOW,BLACK]對應[0,1,2,3]1L << ((Enum<?>)e).ordinal()(爲了方便,這裏稱之爲枚舉值)則表示1*2^(e.ordinal()),Color.RED的ordianl()0,對應枚舉值1*2^0=1,其實就是第ordinal()+1位(從右往左數,個位爲第1位)爲1其它位爲0的十進制數,對應十進制數爲00000001(這裏假設是8bit,實際是long型32bit);
則每個枚舉項表示如下:

枚舉項 序號 1L << ((Enum<?>)e).ordinal() 枚舉值
Color.RED 0 00000001 1
Color.BLUE 1 00000010 2
Color.YELLOW 2 00000100 4
Color.BLACK 3 00001000 8

elements |=就是對添加的不同元素的枚舉值進行求和,相同元素相或保持不變


3.2 remove方法
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;
    elements &= ~(1L << ((Enum<?>)e).ordinal());
    return elements != oldElements;
}

按照之前的枚舉值相加的想法,remove就是從總枚舉值中減去待刪除元素的枚舉值,因爲是位運算,沒有直接相減,使用位操作elements &= ~(1L << ((Enum<?>)e).ordinal());
完成相減操作


3.3 contains方法
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;
}

contains方法就更好理解,每個枚舉項的枚舉值的值都不一樣,且相互之間進行相與操作爲,使用總枚舉值要查詢的枚舉項的枚舉值進行相與操作,如果爲,說明不存在該枚舉項,否則存在

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