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