Enum的簡介
枚舉類型很早就在計(jì)算機(jī)語言中存在了,主要被用來將一組相似的值包含進(jìn)一種類型中涌攻,這種類型的名稱被定義成獨(dú)一無二的類型描述符嫉入,這就是枚舉類型瞎嬉。
在java語言中,枚舉類型是一個(gè)完整功能的類救巷,允許開發(fā)者給枚舉類型添加方法和屬性,同時(shí)也可以提供接口。同時(shí)Java也為Enum提供了高質(zhì)量的實(shí)現(xiàn)挽懦,比如comparable和Serializable接口.
* 其中:Comparable 是排序接口,如果一個(gè)Java類有這個(gè)接口木人,那么只能說明這個(gè)類支持排序信柿。即然實(shí)現(xiàn)Comparable接口的類支持排序,假設(shè)現(xiàn)在存在“實(shí)現(xiàn)Comparable接口的類的對象的List列表(或數(shù)組)醒第,則該List列表(或數(shù)組)可以通過 Collections.sort(或 Arrays.sort)進(jìn)行排序渔嚷。“實(shí)現(xiàn)Comparable接口的類的對象”可以用作“有序映射(如TreeMap)”中的鍵或“有序集合(TreeSet)”中的元素稠曼,而不需要指定比較器形病。
Serializable接口的對象轉(zhuǎn)換成一個(gè)字符序列,并能夠在以后將這個(gè)字節(jié)序列完全恢復(fù)為原來的對象霞幅。而且這個(gè)過程是可以通過網(wǎng)絡(luò)完成的漠吻,也就是說序列化機(jī)制能夠自動(dòng)彌補(bǔ)不同操作系統(tǒng)之間差異。*
Enum的定制
通過類的定義蝗岖,可以給Enum一些復(fù)雜的功能侥猩,例如下面代碼給Enum增加屬性:
public enum DrinkEnum{
// 酒
Wine("a cup of wine ");
//橙汁
Oragen_Juice("a cup of oragen juice")
//Enum對象的drink_class屬性
private String drink_class;
//枚舉對象構(gòu)造函數(shù)
private DrinkEnum(String drink){
? ?this.drink_class=drink;
}
//枚舉對象的drink_class屬性
public String getDrink(){
? ?return this.drink_class;
}
Enum的一些坑
1 Enum 不支持public和protected修飾符的構(gòu)造方法,因此構(gòu)造函數(shù)一定要是private或者friendly的抵赢,這也就約束了枚舉對象是無法在程序中通過直接調(diào)用構(gòu)造函數(shù)進(jìn)行初始化的欺劳。
2 Enum的值是通過運(yùn)行期構(gòu)造出來的對象表示的,因此在集群環(huán)境下铅鲤,每個(gè)jvm構(gòu)造出同義對象划提,但是在做布爾運(yùn)算的時(shí)候有可能有問題,因此要格外注意邢享。在對Enum進(jìn)行比較的時(shí)候鹏往,使用值比對。
Enum的原理
在使用enum創(chuàng)建枚舉類型后骇塘,編譯器會為其生成一個(gè)對應(yīng)的枚舉類伊履,這個(gè)類繼承與java.lang.Enum。舉例如下:
enum Day {
? ?MONDAY, TUESDAY, WEDNESDAY,
? ?THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
編譯后會變成Day.class款违,那么測者反編譯后看到如下:
final class Day extends Enum
{
? ?//編譯器為我們添加的靜態(tài)的values()方法
? ?public static Day[] values()
? ?{
? ? ? ?return (Day[])$VALUES.clone();
? ?}
? ?//編譯器為我們添加的靜態(tài)的valueOf()方法唐瀑,注意間接調(diào)用了Enum也類的valueOf方法
? ?public static Day valueOf(String s)
? ?{
? ? ? ?return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
? ?}
? ?//私有構(gòu)造函數(shù)
? ?private Day(String s, int i)
? ?{
? ? ? ?super(s, i);
? ?}
? ? //前面定義的7種枚舉實(shí)例
? ?public static final Day MONDAY;
? ?public static final Day TUESDAY;
? ?public static final Day WEDNESDAY;
? ?public static final Day THURSDAY;
? ?public static final Day FRIDAY;
? ?public static final Day SATURDAY;
? ?public static final Day SUNDAY;
? ?private static final Day $VALUES[];
? ?static
? ?{ ? ?
? ? ? ?//實(shí)例化枚舉實(shí)例
? ? ? ?MONDAY = new Day("MONDAY", 0);
? ? ? ?TUESDAY = new Day("TUESDAY", 1);
? ? ? ?WEDNESDAY = new Day("WEDNESDAY", 2);
? ? ? ?THURSDAY = new Day("THURSDAY", 3);
? ? ? ?FRIDAY = new Day("FRIDAY", 4);
? ? ? ?SATURDAY = new Day("SATURDAY", 5);
? ? ? ?SUNDAY = new Day("SUNDAY", 6);
? ? ? ?$VALUES = (new Day[] {
? ? ? ? ? ?MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
? ? ? ?});
? ?}
}
可以看到,編譯后生成一個(gè)final類插爹,同時(shí)前面的七個(gè)日期定義成七個(gè)類型哄辣。同時(shí)還有兩個(gè)靜態(tài)方法请梢,分別是values()和 valueOf(),MONDAY枚舉類型對應(yīng)public static final Day MONDAY;力穗,values()方法的作用就是獲取枚舉類中的所有變量毅弧,并作為數(shù)組返回,而valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據(jù)名稱獲取枚舉變量当窗,只不過編譯器生成的valueOf方法更簡潔些只需傳遞一個(gè)參數(shù)够坐。由于values()方法是由編譯器插入到枚舉類中的static方法,所以如果我們將枚舉實(shí)例向上轉(zhuǎn)型為Enum超全,那么values()方法將無法被調(diào)用咆霜,因?yàn)镋num類中并沒有values()方法,valueOf()方法也是同樣的道理嘶朱。
final變量經(jīng)常和static關(guān)鍵字一起使用蛾坯,作為常量。final類通常功能是完整的疏遏,不允許被繼承脉课。
因此枚舉類型,在調(diào)用中如果對內(nèi)部變量使用了set函數(shù)财异,那么就是對一個(gè)常量進(jìn)行了上set操作倘零,也就會導(dǎo)致所有調(diào)用的地方的值都發(fā)生了變化。
EnumSet和EnumMap
EnumSet
EnumSet是一個(gè)針對枚舉類型的高性能Set接口實(shí)現(xiàn)戳寸,但是在其中裝入的枚舉類型必須是同類型的呈驶,在EnumSet中通過bit-vector實(shí)現(xiàn),也就是一個(gè)long型疫鹊。EnumSet支持在遍歷袖瞻。
for (WeekDayEnum day:EnumSet.range(WeekDayEnum.Mon,WeekDayEnum.Sun)){
? ?System.out.println(day)
}
同時(shí)EnumSet還提供了一個(gè)獲取子集的方法:
EnumSet <WeekDayEnum> JobDays = ?EnumSet.of(WeekDayEnum.Mon,WeekDayEnum.Fri);
EnumMap
EnumMap是一個(gè)高性能的Map接口實(shí)現(xiàn),主要管理用枚舉做Key-Value的關(guān)系拆吆,內(nèi)部是通過數(shù)組方式實(shí)現(xiàn)的聋迎。
private static Map<WeekDayEnum,RainbowClolor> schema = new EnumMap<WeekDayEnum.values()[i],RainbowClolor.values()[i]>(WeekDatEnum.class);
關(guān)注測者枣耀,關(guān)注測試