enum枚舉類型
Think in java這本書,不得不說的确是經典,但是今天看到了枚舉,實在忍不住吐槽了,感覺書上的内容完全沒有講出enum的用法,百度後寫此部落格。
enum定義的枚舉類就是class,其定義方法不是通過繼承,我們用關鍵字enum來聲明枚舉類型,不可以通過顯式繼承該抽象類的方式來聲明,并且該類是一個不可以被繼承的final類。其枚舉值都是該枚舉類的類靜态常量,注意:這些枚舉值都是public static final的,是以可以通過可以通過 Enum 類型名直接引用該常量,如 類名.常量名,是以枚舉類中的枚舉值最好全部大寫。
一個枚舉類的枚舉對象裡面的值都必須是唯一的,可以把相同類型的常量分組到一個枚舉類型裡。枚舉的一個突出優點在于它能夠保證單例,它的這個優點讓它和switch成了絕配,在jdk1.5之前,switch隻能支援int和char類型,局限了switch的使用範圍。當switch可以和enum搭配使用的時候,這個限制被突破了,理論上我們可以借助enum對任意具有相同類型的對象使用switch。
Think in java上這一節的練習是建立一個包含紙币最小類型的enum并為其寫一個switch語句,對于每一個case輸出該特定貨币的描述,這個問題很好的解釋了enum的作用,最小貨币就是0.1,0.2,0.5,1,2,5這些double資料,如果沒有enum的配合,switch是不能接受double型作為變量的,下面在代碼中講解enum的用法。
首先是enum的定義類
/* 枚舉也可以象一般的類一樣添加方法和屬性,
* 你可以為它添加靜态和非靜态的屬性或方法,
* 這一切都象你在一般的類中做的那樣.
* 枚舉類是通過enum關鍵字聲明來定義的 */
public enum Enum_Money {
// 枚舉清單必須寫在最前面,否則編譯出錯,枚舉清單隻支援String類型,但是允許在枚舉值後用括号添加構造。如果隻是最普通的枚舉沒有其他方法枚舉結尾可以不加分号,否則必須加
Not(0.1),MILD(0.2),MEDIUM(0.5),HOT(1),FLAMING(2);
private double money;
/*通過括号指派,而且必須有帶參構造器和一屬性跟方法,否則編譯出錯
* 指派必須是都指派或都不指派,不能一部分指派一部分不指派
* 如果不指派則不能寫構造器,指派編譯也出錯*/
//構造器預設也隻能是private, 進而保證構造函數隻能在内部使用
Enum_Money(double money){
this.money=money;
}
public double getReturn(){
return money;
}
}
然後是調用類
public class Test_Enum {
public static void main(String[] ARGS){
/*通過values()獲得枚舉值的數組,按照enum常量聲明的順序*/
for(Enum_Money money:Enum_Money.values())
/*ordinal()傳回枚舉值在枚舉中的索引位置,從0開始,順序為enum聲明的順序*/
System.out.println(money.getReturn()+" "+money.ordinal());
/*
* 枚舉類型是一種類型,用于定義變量,以限制變量的指派 指派時通過"枚舉名.值"來取得相關枚舉中的值
*/
Enum_Money money = Enum_Money.MEDIUM;
switch (money) {
case Not:
System.out.println("1毛");
break;
case MEDIUM:
System.out.println("2毛");
break;
default:
break;
}
}
}
下面是enum類的源碼分析
1. public abstract class Enum<E extends Enum<E>>
2. implements Comparable<E>, Serializable {
3.
4. private final String name;
5.
6. // 目前枚舉常量名稱
7. public final String name() {
8. return name;
9. }
10.
11. private final int ordinal;
12.
13. // 目前枚舉常量次序,從0開始
14. public final int ordinal() {
15. return ordinal;
16. }
17.
18. // 專有構造器,我們無法調用。該構造方法用于由響應枚舉類型聲明的編譯器發出的代碼。
19. protected Enum(String name, int ordinal) {
20. this.name = name;
21. this.ordinal = ordinal;
22. }
23.
24. // 傳回枚舉常量的名稱,預設是傳回name值。可以重寫該方法,輸出更加友好的描述。
25. public String toString() {
26. return name;
27. }
28.
29. // 比較目前枚舉常量是否和指定的對象相等。因為枚舉常量是單例的,是以直接調用==操作符。子類不可以重寫該方法。
30. public final boolean equals(Object other) {
31. return this==other;
32. }
33.
34. // 傳回該枚舉常量的哈希碼。和equals一緻,該方法不可以被重寫。
35. public final int hashCode() {
36. return super.hashCode();
37. }
38.
39. // 因為枚舉常量是單例的,是以不允許克隆。
40. protected final Object clone() throws CloneNotSupportedException {
41. throw new CloneNotSupportedException();
42. }
43.
44. // 比較該枚舉常量和指定對象的大小。它們的類型要相同,根據它們在枚舉聲明中的先後順序來傳回大小(前面的小,後面的大)。子類不可以重寫該方法
45. public final int compareTo(E o) {
46. Enum other = (Enum)o;
47. Enum self = this;
48. if (self.getClass() != other.getClass() && // optimization
49. self.getDeclaringClass() != other.getDeclaringClass())
50. throw new ClassCastException();
51. return self.ordinal - other.ordinal;
52. }
53.
54. // 得到枚舉常量所屬枚舉類型的Class對象
55. public final Class<E> getDeclaringClass() {
56. Class clazz = getClass();
57. Class zuper = clazz.getSuperclass();
58. return (zuper == Enum.class) ? clazz : zuper;
59. }
60.
61. // 傳回帶指定名稱的指定枚舉類型的枚舉常量。名稱必須與在此類型中聲明枚舉常量所用的辨別符完全比對。不允許使用額外的空白字元。
62. public static <T extends Enum<T>> T valueOf(Class<T> enumType,
63. String name) {
64. T result = enumType.enumConstantDirectory().get(name);
65. if (result != null)
66. return result;
67. if (name == null)
68. throw new NullPointerException("Name is null");
69. throw new IllegalArgumentException(
70. "No enum const " + enumType +"." + name);
71. }
72.
73. // 不允許反序列化枚舉對象
74. private void readObject(ObjectInputStream in) throws IOException,
75. ClassNotFoundException {
76. throw new InvalidObjectException("can't deserialize enum");
77. }
78.
79. // 不允許反序列化枚舉對象
80. private void readObjectNoData() throws ObjectStreamException {
81. throw new InvalidObjectException("can't deserialize enum");
82. }
83.
84. // 枚舉類不可以有finalize方法,子類不可以重寫該方法
85. protected final void finalize() { }
86. }