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() 枚舉值
枚舉項 | 序號 | 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方法就更好理解,每個枚舉項的枚舉值的值都不一樣
,且相互之間
進行相與
操作為0
,使用總枚舉值
與要查詢的枚舉項的枚舉值
進行相與
操作,如果為0
,說明不存在
該枚舉項,否則存在