1. 概述
枚舉(enum)全寫為的全稱為:enumeration。是jdk1.5才新引進(jìn)的概念,在Java中enum的有與C、C++相似的基本用法,也有很多擴(kuò)展的用法。
盡管枚舉類型看著像一種新的數(shù)據(jù)類型,但實(shí)際上它是一種受限制的類(繼承自java.lang.Enum)。
publicenumColorEnum{//相當(dāng)于創(chuàng)建了5個(gè)實(shí)例,調(diào)用了5次 Enum(String name, int ordinal)RED,WHITE,BLUE,BLACK,GREEN}
1
2
3
4
經(jīng)過編譯器編譯后產(chǎn)生的是一個(gè)class文件,該class文件經(jīng)過反編譯軟件編譯后可以看到實(shí)際上生成了一個(gè)類:
publicclasscom.com.yarward.design.ColorEnumextendsjava.lang.Enum{publicstaticfinalcom.com.yarward.design.ColorEnum RED;publicstaticfinalcom.com.yarward.design.ColorEnum WHITE;publicstaticfinalcom.com.yarward.design.ColorEnum BLUE;publicstaticfinalcom.com.yarward.design.ColorEnum BLACK;publicstaticfinalcom.com.yarward.design.ColorEnum GREEN;static{};publicstaticcom.com.yarward.design.ColorEnum[]values();publicstaticcom.com.yarward.design.ColorEnumvalueOf(java.lang.String);? ? ....}
1
2
3
4
5
6
7
8
9
10
11
/** * This is the common base class of all Java language enumeration types. * *
Note that when using an enumeration type as the type of a set * or as the type of the keys in a map, specialized and efficient * {@linkplain java.util.EnumSet set} and {@linkplain * java.util.EnumMap map} implementations are available. * * @since1.5 */publicabstractclassEnum>implementsComparable,Serializable{...}
1
2
3
4
5
6
7
8
9
10
11
12
在未引入enum之前,我們定義常量的時(shí)候總是使用這樣的方式:public final static 類型....,在引入了枚舉類型之后,我們可以將一組相似屬性統(tǒng)一組織、管理管理,并包含一些自己的方法:
name():返回枚舉常量的名稱。
ordinal():返回枚舉常量的時(shí)序,0、1、2……。
getDeclaringClass():返回實(shí)例所屬的enum類型。
equals(Object other):判斷兩個(gè)enum實(shí)例是否相等,也可用用==號(hào)來進(jìn)行判斷。
注意不能用直接用數(shù)字常量與枚舉類型直接比較。
因?yàn)楦割怑num實(shí)現(xiàn)了Comparable和Serializable的接口,因此也可以使用compareTo()方法。
例:
ColorEnum colorEnumWhite = ColorEnum.WHITE;ColorEnum colorEnumRed = ColorEnum.RED;Log.d("test enum","enum colorEnumRed.toString() is "+ colorEnumRed.toString());Log.d("test enum","enum colorEnumWhite is "+ colorEnumWhite);Log.d("test enum","enum constant name is "+ colorEnumWhite.name());Log.d("test enum","enum constant ordinal is "+ colorEnumWhite.ordinal());Log.d("test enum","enum getDeclaringClass is "+ colorEnumWhite.getDeclaringClass());Log.d("test enum","enum colorEnumWhite = colorEnumRed "+ colorEnumWhite.equals(colorEnumRed));Log.d("test enum","enum colorEnumWhite = 1 "+ colorEnumWhite.equals(1));Log.d("test enum","enum colorEnumWhite compareTo colorEnumRed "+ colorEnumWhite.compareTo(colorEnumRed));
1
2
3
4
5
6
7
8
9
10
11
輸出結(jié)果:
enumcolorEnumRed.toString() is REDenumcolorEnumWhite is WHITEconstant name is WHITEconstant ordinal is1getDeclaringClass is class com.yarward.design.MainActivity$ColorEnumenumcolorEnumWhite = colorEnumRedfalseenumcolorEnumWhite =1falseenumcolorEnumWhite compareTo colorEnumRed1
1
2
3
4
5
6
7
8
在使用enum時(shí)需要注意:
定義的枚舉類型不可再繼承其他的類型的類,因?yàn)樗呀?jīng)繼承了java.lang.Enum。
前面介紹過,枚舉也是一種類,是一種受限制的類,不能在繼承其他任何類的類。因此它也具有類應(yīng)該有的特性。
java中的枚舉與c/c++中的枚舉不同,c/c++可以顯示的為枚舉類型賦值,而java中的枚舉不可以。
/*C/C++可以顯示的給枚舉類型賦值*/typedef enum _Number{
? one = 1,
? two,
? three,
? ten = 10
}Number;
1
2
3
4
5
6
7
Java雖然不能直接為實(shí)例賦值,但是它有更優(yōu)秀的解決方案:為 enum 添加方法來間接實(shí)現(xiàn)顯示賦值。枚舉類可以有自己的成員、構(gòu)造方法、普通方法、抽象方法、靜態(tài)方法。
唯一用起來比較別扭的一點(diǎn)是,enum相當(dāng)于把類的實(shí)例化(枚舉常量)放到了類聲明的內(nèi)部,這些枚舉常量也可以重寫枚舉類型中的方法。
publicenumWeekEnum{//定義枚舉常量Mon(true),Tue(true),Wen(true),Thu(true),//定義枚舉常量的時(shí)候可以重寫枚舉類型中方法Fri(true){@OverridepublicStringhelloEnum() {return"sad to work";? ? ? ? }? ? },? ? Sat(false),Sun(false);//枚舉類型中可以有成員變量privatebooleanmIsWork;//枚舉類型中可以有構(gòu)造函數(shù)privateWeekEnum(booleanisWork){this.mIsWork = isWork;? ? }//枚舉類型中可以有成員方法publicbooleanisWork(){returnmIsWork;? ? }publicStringhelloEnum(){return"happy to work";? ? }//枚舉類型中可以靜態(tài)方法publicstaticStringinfoPrint(){return"Monday to Sunday!";? ? } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
WeekEnum tue = WeekEnum.Tue;WeekEnum fri = WeekEnum.Fri;WeekEnum sat = WeekEnum.Sat;Log.d("test enum","enum static method :"+ WeekEnum.infoPrint());Log.d("test enum","enum tue.helloEnum :"+ tue.helloEnum());Log.d("test enum","enum fri.helloEnum :"+ fri.helloEnum());Log.d("test enum","enum fri is work? "+ fri.isWork());Log.d("test enum","enum sat is work? "+ sat.isWork());
1
2
3
4
5
6
7
8
9
enumstaticmethod :Monday to Sunday!enumtue.helloEnum :happy to workenumfri.helloEnum :sad to workenumfri is work?trueenumsat is work?false
1
2
3
4
5
同樣作為類,枚舉類型也可以實(shí)現(xiàn)接口。用法和普通類的用法一致。
publicinterfaceIDoSomeThing{publicvoiddoJobs();}
1
2
3
publicenumWeekEnum implements IDoSomeThing{? ? Mon(true),Tue(true),Wen(true),Thu(true),Fri(true){@OverridepublicStringhelloEnum() {return"sad to work";? ? ? ? }? ? },? ? Sat(false){@OverridepublicvoiddoJobs() {? ? ? ? ? ? Log.d("test enum","I am at resting");? ? ? ? }? ? },Sun(false);? ...? ...@OverridepublicvoiddoJobs() {? ? ? ? Log.d("test enum","I am at working");? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fri.doJobs();
sat.doJobs();
1
2
I am at working
I am at resting
1
2
如果enum不添加任何方法的話,枚舉的默認(rèn)值為:從0開始的有序數(shù)值,每次遞增1。
如果定義的枚舉類型沒有任何方法的話,可以在最后一個(gè)實(shí)例(常量)后加”,” 或”;” 或什么都不加。
注意:如果枚舉類中添加了方法,則必須在最后一個(gè)實(shí)例后添加”;”
以下三種方式定義都可以:
enumColorEnum{ RED, WHITE, BLUE, BLACK, GREEN }enumColorEnum{ RED, WHITE, BLUE, BLACK, GREEN, }enumColorEnum{ RED, WHITE, BLUE, BLACK, GREEN; }
1
2
3
enumSignal {? ? ? GREEN, YELLOW, RED? }publicclassTrafficLight{Signal color = Signal.RED;publicvoidchange() {switch(color) {caseRED:? ? ? ? ? ? ? color = Signal.GREEN;break;caseYELLOW:? ? ? ? ? ? ? color = Signal.RED;break;caseGREEN:? ? ? ? ? ? ? color = Signal.YELLOW;break;? ? ? ? ? }? ? ? }? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以將類型相近的枚舉通過接口或類組織起來,但是一般用接口方式進(jìn)行組織。
原因是:Java接口在編譯時(shí)會(huì)自動(dòng)為enum類型加上public static修飾符;Java類在編譯時(shí)會(huì)自動(dòng)為enum類型加上static修飾符。看出差異了嗎?
沒錯(cuò),就是說,在類中組織enum,如果你不給它修飾為public,那么只能在本包中進(jìn)行訪問。
在接口中不加public static修飾詞,也能在其他包中被引用。
publicinterfaceINumberEnum{publicintgetCode();publicStringgetDescription();}
1
2
3
4
publicinterfacePlant{enumVegetable implements INumberEnum {? ? ? ? POTATO(0,"土豆"),? ? ? ? TOMATO(0,"西紅柿");? ? ? ? Vegetable(intnumber, String description) {this.code = number;this.description = description;? ? ? ? }privateintcode;privateString description;@OverridepublicintgetCode() {return0;? ? ? ? }@OverridepublicStringgetDescription() {returnnull;? ? ? ? }? ? }enumFruit implements INumberEnum {? ? ? ? APPLE(0,"蘋果"),? ? ? ? ORANGE(0,"桔子"),? ? ? ? BANANA(0,"香蕉");? ? ? ? Fruit(intnumber, String description) {this.code = number;this.description = description;? ? ? ? }privateintcode;privateString description;@OverridepublicintgetCode() {return0;? ? ? ? }@OverridepublicStringgetDescription() {returnnull;? ? ? ? }? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
這種枚舉通過枚舉嵌套枚舉的方式,將枚舉實(shí)例(常量)分類處理,雖然沒有通過switch語句使用簡(jiǎn)潔,但是更加靈活。
enumPayrollDay {? ? MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(? ? ? ? ? ? PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(? ? ? ? ? ? PayType.WEEKEND), SUNDAY(PayType.WEEKEND);privatefinalPayType payType;? ? PayrollDay(PayType payType) {this.payType = payType;? ? }doublepay(doublehoursWorked,doublepayRate) {returnpayType.pay(hoursWorked, payRate);? ? }// 策略枚舉privateenumPayType {? ? ? ? WEEKDAY {doubleovertimePay(doublehours,doublepayRate) {returnhours <= HOURS_PER_SHIFT ?0: (hours - HOURS_PER_SHIFT)? ? ? ? ? ? ? ? ? ? ? ? * payRate /2;? ? ? ? ? ? }? ? ? ? },? ? ? ? WEEKEND {doubleovertimePay(doublehours,doublepayRate) {returnhours * payRate /2;? ? ? ? ? ? }? ? ? ? };privatestaticfinalintHOURS_PER_SHIFT =8;abstractdoubleovertimePay(doublehrs,doublepayRate);doublepay(doublehoursWorked,doublepayRate) {doublebasePay = hoursWorked * payRate;returnbasePay + overtimePay(hoursWorked, payRate);? ? ? ? }? ? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Log.d("test enum","時(shí)薪100的人在周五工作8小時(shí)的收入:"+ PayrollDay.FRIDAY.pay(8.0,100));Log.d("test enum","時(shí)薪100的人在周六工作8小時(shí)的收入:"+ PayrollDay.SATURDAY.pay(8.0,100));
1
2
EnumSet是枚舉類型的高性能Set實(shí)現(xiàn)。它要求放入它的枚舉常量必須屬于同一枚舉類型。它的使用與其他的set沒有什么不同,只是在構(gòu)造的時(shí)候有一些特殊而已。
publicvoidshowEnumSetValue(EnumSet enumSet){? ? Log.d("enum test","enum set value is : "+ Arrays.toString(enumSet.toArray()));}
1
2
3
//創(chuàng)建一個(gè)之類enum類型的空集合EnumSet enumEnumSet = EnumSet.noneOf(ColorEnum.class);showEnumSetValue(enumEnumSet);enumEnumSet.add(ColorEnum.BLACK);enumEnumSet.add(ColorEnum.BLUE);showEnumSetValue(enumEnumSet);//創(chuàng)建一個(gè)指定enum類型的所有實(shí)例的集合EnumSet enumEnumSet1 = EnumSet.allOf(ColorEnum.class);showEnumSetValue(enumEnumSet1);//創(chuàng)建一個(gè)指定enum初始化內(nèi)容的集合EnumSet enumEnumSet2 = EnumSet.of(ColorEnum.GREEN,ColorEnum.WHITE);showEnumSetValue(enumEnumSet2);//創(chuàng)建指定類型,指定范圍的集合,包含邊界數(shù)據(jù)EnumSet enumEnumSet3 = EnumSet.range(ColorEnum.BLUE,ColorEnum.GREEN);showEnumSetValue(enumEnumSet3);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enumset value is : []enumset value is : [BLUE, BLACK]enumset value is : [RED, WHITE, BLUE, BLACK, GREEN]enumset value is : [WHITE, GREEN]enumset value is : [BLUE, BLACK, GREEN]
1
2
3
4
5
EnumMap是專門為枚舉類型量身定做的Map實(shí)現(xiàn)。雖然使用其它的Map實(shí)現(xiàn)(如HashMap)也能完成枚舉類型實(shí)例到值得映射,但是使用EnumMap會(huì)更加高效:它只能接收同一枚舉類型的實(shí)例作為鍵值,并且由于枚舉類型實(shí)例的數(shù)量相對(duì)固定并且有限,所以EnumMap使用數(shù)組來存放與枚舉類型對(duì)應(yīng)的值。這使得EnumMap的效率非常高。
EnumMap enumStringEnumMap =newEnumMap(ColorEnum.class);enumStringEnumMap.put(ColorEnum.RED,"紅色");enumStringEnumMap.put(ColorEnum.BLUE,"藍(lán)色");enumStringEnumMap.put(ColorEnum.GREEN,"綠色");for(Map.Entry enumStringEntry : enumStringEnumMap.entrySet()){? ? Log.d("enum test","enum map key: "+enumStringEntry.getKey().name()+" value "+ enumStringEntry.getValue());}
1
2
3
4
5
6
7
8
enummap key: RED value 紅色enummap key: BLUE value 藍(lán)色enummap key: GREEN value 綠色