EnumSet是Java枚舉類型的泛型容器,Java既然有了SortedSet、TreeSet、HashSet等容器,為何還要多一個EnumSet<T>呢?答案肯定是EnumSet有一定的特性,舉個例子,EnumSet的速度很快。其他特性就不一一列舉了,畢竟本文的內容不是介紹EnumSet的特性。
首先以事實說話,存在這樣一個EnumSet,它有50個枚舉值T0~T49,將50個值插入到容器(HashSet、EnumSet)中,為一個操作,將50個枚舉值移出做為第二個操作。把第一個和第二個操作執行的總時間設定為一個周期,拿HashSet操作的一個周期和EnumSet的一個周期做比較自然沒什么意義,所以我們用50個周期的和做為比較,HashSet耗費9ms,EnumSet耗費4ms(這個結果只說明同樣的操作EnumSet比HashSet更快,不做為其他參考依據,因為這個時間不是線程獨占時間)。以下是代碼和結果:
public class EnumSetTest{ private static EnumTest[] enumTestArr = EnumTest.values(); public static void main(String[] args) { Set set = new HashSet<EnumTest>(); int i = 0; SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); System.out.println("HashSet...Begin " + df.format(new Date())); while (i <= 1000) { addEnumerate(set); removeEnumerate(set); i++; } System.out.println("HashSet...End " + df.format(new Date())); EnumSet<EnumTest> enumSet = EnumSet.noneOf(EnumTest.class); i = 0; System.out.println("EnumSet...Begin " + df.format(new Date())); while (i <= 1000) { addEnumerate(enumSet); removeEnumerate(enumSet); i++; } System.out.println("EnumSet...End " + df.format(new Date())); } /* * HashSet...Begin 2015-01-03 21:11:51.579 * HashSet...End 2015-01-03 21:11:51.588 * EnumSet...Begin 2015-01-03 21:11:51.589 * EnumSet...End 2015-01-03 21:11:51.593 * */ private static void addEnumerate(Set set) { for (EnumTest t : enumTestArr) { set.add(t); } } private static void removeEnumerate(Set set) { for (EnumTest t : enumTestArr) { set.remove(t); } } }
那為什么EnumSet比較快呢,EnumSet是一個抽象方法,本次測試是用到的EnumSet的實現RegularEnumSet,RegularEnumSet add方法的源碼如下:
public boolean add(E e) { typeCheck(e); long oldElements = elements; elements |= (1L << ((Enum)e).ordinal()); return elements != oldElements;
從Add方法的源碼可以看出add方法實際只是對長整型數據element做了一個操作,也就是說EnumSet實際上將枚舉值保存在一個長整型數據上。沒個枚舉值占用一bit。每次添加做的主要操作是1、類型檢查 2、 添加枚舉值 3、判斷枚舉值是否已經添加過了。
現在模擬一個場景來說明EnumSet工作原理。新建一個EnumSet(Set1),並向Set1中添加EnumTest.T3(ordinal:3),代碼如下
EnumSet<EnumTest> set1 = EnumSet.noneOf(EnumTest.class); set1.add(EnumTest.T3);
element本來有64個bit,這里就簡略畫了。這里有一個問題,就是枚舉值的個數超過64個怎么辦?超過64個了就用EnumSet的另一個實現JumboEnumSet。
本文到此就結束了,至於JumboEnumSet的工作原理和RegularEnumSet其他方法的工作原理請自行探索吧。所有源碼都可以在http://grepcode.com/ 找到。