Junit單元測試遇見的一個列舉型別的坑(列舉型別詳解)
Enum的簡介
列舉型別很早就在計算機語言中存在了,主要被用來將一組相似的值包含進一種型別中,這種型別的名稱被定義成獨一無二的型別描述符,這就是列舉型別。
在java語言中,列舉型別是一個完整功能的類,允許開發者給列舉型別新增方法和屬性,同時也可以提供介面。同時Java也為Enum提供了高質量的實現,比如comparable和Serializable介面.
* 其中:Comparable 是排序介面,如果一個Java類有這個介面,那麼只能說明這個類支援排序。即然實現Comparable介面的類支援排序,假設現在存在“實現Comparable介面的類的物件的List列表(或陣列),則該List列表(或陣列)可以通過 Collections.sort(或 Arrays.sort)進行排序。“實現Comparable介面的類的物件”可以用作“有序對映(如TreeMap)”中的鍵或“有序集合(TreeSet)”中的元素,而不需要指定比較器。 Serializable介面的物件轉換成一個字元序列,並能夠在以後將這個位元組序列完全恢復為原來的物件。而且這個過程是可以通過網路完成的,也就是說序列化機制能夠自動彌補不同作業系統之間差異。 *
Enum的定製
通過類的定義,可以給Enum一些複雜的功能,例如下面程式碼給Enum增加屬性:
public enum DrinkEnum{

Enum的一些坑
-
1 Enum 不支援 public 和 protected 修飾符的構造方法,因此建構函式一定要是 private 或者 friendly 的,這也就約束了列舉物件是無法在程式中通過直接呼叫建構函式進行初始化的。
-
2 Enum 的值是通過執行期構造出來的物件表示的,因此在叢集環境下,每個 jvm 構造出同義物件,但是在做布林運算的時候有可能有問題,因此要格外注意。在對 Enum 進行比較的時候,使用值比對。
Enum的原理
在使用enum建立列舉型別後,編譯器會為其生成一個對應的列舉類,這個類繼承與java.lang.Enum。舉例如下:
Enum的原理
在使用enum建立列舉型別後,編譯器會為其生成一個對應的列舉類,這個類繼承與java.lang.Enum。舉例如下:

可以看到,編譯後生成一個final類,同時前面的七個日期定義成七個型別。同時還有兩個靜態方法,分別是values()和 valueOf(),MONDAY列舉型別對應public static final Day MONDAY;,values()方法的作用就是獲取列舉類中的所有變數,並作為陣列返回,而valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據名稱獲取列舉變數,只不過編譯器生成的valueOf方法更簡潔些只需傳遞一個引數。由於values()方法是由編譯器插入到列舉類中的static方法,所以如果我們將列舉例項向上轉型為Enum,那麼values()方法將無法被呼叫,因為Enum類中並沒有values()方法,valueOf()方法也是同樣的道理。
final變數經常和static關鍵字一起使用,作為常量。final類通常功能是完整的,不允許被繼承。
因此列舉型別,在呼叫中如果對內部變數使用了set函式,那麼就是對一個常量進行了上set操作,也就會導致所有呼叫的地方的值都發生了變化。
EnumSet和EnumMap
EnumSet
EnumSet是一個針對列舉型別的高效能Set介面實現,但是在其中裝入的列舉型別必須是同類型的,在EnumSet中通過bit-vector實現,也就是一個long型。EnumSet支援在遍歷。

同時EnumSet還提供了一個獲取子集的方法:
EnumMap
EnumMap是一個高效能的Map介面實現,主要管理用列舉做Key-Value的關係,內部是通過陣列方式實現的。
-
private static Map < WeekDayEnum , RainbowClolor > schema = new EnumMap < WeekDayEnum . values ()[ i ], RainbowClol