<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d7e2a68c7c.css">
<div class="htmledit_views" id="content_views">
枚舉(enum),是指一個經過排序的、被打包成一個單一實體的項列表。一個枚舉的實例可以使用枚舉項列表中任意單一項的值。枚舉在各個語言當中都有着廣泛的應用,通常用來表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量。Java從JDK5開始,引入了對枚舉的支持。
在枚舉出現之前,如果想要表示一組特定的離散值,往往使用一些常量。例如:
-
package com.fhp.enumexample;
-
-
public
class Entity {
-
-
public
static
final
int VIDEO =
1;
//視頻
-
public
static
final
int AUDIO =
2;
//音頻
-
public
static
final
int TEXT =
3;
//文字
-
public
static
final
int IMAGE =
4;
//圖片
-
-
private
int id;
-
private
int type;
-
-
public int getId() {
-
return id;
-
}
-
public void setId(int id) {
-
this.id = id;
-
}
-
public int getType() {
-
return type;
-
}
-
public void setType(int type) {
-
this.type = type;
-
}
-
-
-
}
當然,常量也不僅僅局限於int型,諸如char和String等也是不在少數。然而,無論使用什么樣的類型,這樣做都有很多的壞處。這些常量通常都是連續、有無窮多個值的量,而類似這種表示類別的量則是離散的,並且通常情況下只有有限個值。用連續的量去表示離散量,會產生很多問題。例如,針對上述的Entity類,如果要對Entity對象的type屬性進行賦值,一般會采用如下方法:
-
Entity e =
new Entity();
-
e.setId(
10);
-
e.setType(
2);
這樣做的缺點有:(1)代碼可讀性差、易用性低。由於setType()方法的參數是int型的,在閱讀代碼的時候往往會讓讀者感到一頭霧水,根本不明白這個2到底是什么意思,代表的是什么類型。當然,要保證可讀性,還有這樣一個辦法:
e.setType(Entity.AUDIO);
而這樣的話,問題又來了。這樣做,客戶端必須對這些常量去建立理解,才能了解如何去使用這個東西。說白了,在調用的時候,如果用戶不到Entity類中去看看,還真不知道這個參數應該怎么傳、怎么調。像是setType(2)這種用法也是在所難免,因為它完全合法,不是每個人都能夠建立起用常量名代替數值,從而增加程序可讀性、降低耦合性的意識。
(2)類型不安全。在用戶去調用的時候,必須保證類型完全一致,同時取值范圍也要正確。像是setType(-1)這樣的調用是合法的,但它並不合理,今后會為程序帶來種種問題。也許你會說,加一個有效性驗證嘛,但是,這樣做的話,又會引出下面的第(3)個問題。
(3)耦合性高,擴展性差。假如,因為某些原因,需要修改Entity類中常量的值,那么,所有用到這些常量的代碼也就都需要修改——當然,要仔細地修改,萬一漏了一個,那可不是開玩笑的。同時,這樣做也不利於擴展。例如,假如針對類別做了一個有效性驗證,如果類別增加了或者有所變動,則有效性驗證也需要做對應的修改,不利於后期維護。
枚舉就是為了這樣的問題而誕生的。它們給出了將一個任意項同另一個項相比較的能力,並且可以在一個已定義項列表中進行迭代。枚舉(在Jave中簡稱為enum)是一個特定類型的類。所有枚舉都是Java中的新類java.lang.Enum的隱式子類。此類不能手工進行子類定義。一個簡單的枚舉可以是這樣:
-
package com.fhp.enumexample;
-
-
public
enum TypeEnum {
-
VIDEO, AUDIO, TEXT, IMAGE
-
}
上面的Entity類就可以改成這樣:
-
package com.fhp.enumexample;
-
-
public
class Entity {
-
-
private
int id;
-
private TypeEnum type;
-
-
public int getId() {
-
return id;
-
}
-
public void setId(int id) {
-
this.id = id;
-
}
-
-
public TypeEnum getType() {
-
return type;
-
}
-
public void setType(TypeEnum type) {
-
this.type = type;
-
}
-
}
在為Entity對象賦值的時候,就可以這樣:
-
Entity e =
new Entity();
-
e.setId(
10);
-
e.setType(TypeEnum.AUDIO);
怎么看,都是好了很多。在調用setType()時,可選值只有四個,否則會出現編譯錯誤,因此可以看出,枚舉是類型安全的,不會出現取值范圍錯誤的問題。同時,客戶端不需要建立對枚舉中常量值的了解,使用起來很方便,並且可以容易地對枚舉進行修改,而無需修改客戶端。如果常量從枚舉中被刪除了,那么客戶端將會失敗並且將會收到一個錯誤消息。枚舉中的常量名稱可以被打印,因此除了僅僅得到列表中項的序號外還可以獲取更多信息。這也意味着常量可用作集合的名稱,例如HashMap。
因為在Java中一個枚舉就是一個類,它也可以有屬性和方法,並且實現接口。只是所有的枚舉都繼承自java.lang.Enum類,因此enum不可以再繼承其他的類。
下面給出在枚舉中聲明屬性和方法的示例:
-
package com.fhp.enumexample;
-
-
public
enum TypeEnum {
-
VIDEO(
1), AUDIO(
2), TEXT(
3), IMAGE(
4);
-
-
int value;
-
-
TypeEnum(
int value) {
-
this.value = value;
-
}
-
-
public int getValue() {
-
return value;
-
}
-
}
在這個枚舉中,每個枚舉的值都有一個對應的int型字段,而且不同的枚舉值也會有不同的int數值。同時,它和普通的類一樣,可以聲明構造器和各種各樣的方法。如:
-
TypeEnum type = TypeEnum.TEXT;
//type的value屬性值為3。
-
System.out.println(type.getValue());
//屏幕輸出3。
如果要為每個枚舉值指定屬性,則在枚舉中必須聲明一個參數為屬性對應類型的構造方法(不能是public)。否則編譯器將給出The constructor TypeEnum(int, String) is undefined的錯誤。在此例中,屬性為int型,因此構造方法應當為int型。除此之外,還可以為枚舉指定多個屬性,如:
-
package com.fhp.enumexample;
-
-
public
enum TypeEnum {
-
VIDEO(
1,
"視頻"), AUDIO(
2,
"音頻"), TEXT(
3,
"文本"), IMAGE(
4,
"圖像");
-
-
int value;
-
String name;
-
-
TypeEnum(
int value, String name) {
-
this.value = value;
-
this.name = name;
-
}
-
-
public int getValue() {
-
return value;
-
}
-
-
public String getName() {
-
return name;
-
}
-
}
enum還內置了許多方法,常用的如下:
int compareTo(E o)
比較此枚舉與指定對象的順序。
Class<E> getDeclaringClass()
返回與此枚舉常量的枚舉類型相對應的 Class 對象。
String name()
返回此枚舉常量的名稱,在其枚舉聲明中對其進行聲明。
int ordinal()
返回枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量序數為零)。
String toString()
返回枚舉常量的名稱,它包含在聲明中。
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
返回帶指定名稱的指定枚舉類型的枚舉常量。
static T[] values()
返回該枚舉的所有值。
現在,假設要為該枚舉實現一個根據整數值生成枚舉值的方法,可以這樣做:
-
package com.fhp.enumexample;
-
-
public
enum TypeEnum {
-
VIDEO(
1,
"視頻"), AUDIO(
2,
"音頻"), TEXT(
3,
"文本"), IMAGE(
4,
"圖像");
-
-
int value;
-
String name;
-
-
TypeEnum(
int value, String name) {
-
this.value = value;
-
this.name = name;
-
}
-
-
public int getValue() {
-
return value;
-
}
-
-
public String getName() {
-
return name;
-
}
-
-
public static TypeEnum getByValue(int value) {
-
for(TypeEnum typeEnum : TypeEnum.values()) {
-
if(typeEnum.value == value) {
-
return typeEnum;
-
}
-
}
-
throw
new IllegalArgumentException(
"No element matches " + value);
-
}
-
}
getByValue(int)即為整數值轉枚舉值的方法。調用values()方法獲取到該枚舉下的所有值,然后遍歷該枚舉下面的每個值和給定的整數是否匹配,若匹配直接返回,若無匹配值則拋出IllegalArgumentException異常,表示參數不合法,兼有有效性驗證的作用。
綜上,我們可以看到,在JDK5中新引入的枚舉完美地解決了之前通過常量來表示離散量所帶來的問題,大大加強了程序的可讀性、易用性和可維護性,並且在此基礎之上又進行了擴展,使之可以像類一樣去使用,更是為Java對離散量的表示上升了一個台階。因此,如果在Java中需要表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量,應當盡量舍棄常量表示的做法,而將枚舉作為首要的選擇。