浅谈在Java开发中的枚举的作用和用法
2019獨角獸企業重金招聘Python工程師標準>>>
在枚舉出現之前,如果想要表示一組特定的離散值,往往使用一些常量。例如: [java] view plain copy
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屬性進行賦值,一般會采用如下方法:
[java] view plain copy
Entity e = new Entity(); e.setId(10); e.setType(2);這樣做的缺點有:(1)代碼可讀性差、易用性低。由于setType()方法的參數是int型的,在閱讀代碼的時候往往會讓讀者感到一頭霧水,根本不明白這個2到底是什么意思,代表的是什么類型。當然,要保證可讀性,還有這樣一個辦法:
[java] view plain copy
e.setType(Entity.AUDIO);而這樣的話,問題又來了。這樣做,客戶端必須對這些常量去建立理解,才能了解如何去使用這個東西。說白了,在調用的時候,如果用戶不到Entity類中去看看,還真不知道這個參數應該怎么傳、怎么調。像是setType(2)這種用法也是在所難免,因為它完全合法,不是每個人都能夠建立起用常量名代替數值,從而增加程序可讀性、降低耦合性的意識。
(2)類型不安全。在用戶去調用的時候,必須保證類型完全一致,同時取值范圍也要正確。像是setType(-1)這樣的調用是合法的,但它并不合理,今后會為程序帶來種種問題。也許你會說,加一個有效性驗證嘛,但是,這樣做的話,又會引出下面的第(3)個問題。
(3)耦合性高,擴展性差。假如,因為某些原因,需要修改Entity類中常量的值,那么,所有用到這些常量的代碼也就都需要修改——當然,要仔細地修改,萬一漏了一個,那可不是開玩笑的。同時,這樣做也不利于擴展。例如,假如針對類別做了一個有效性驗證,如果類別增加了或者有所變動,則有效性驗證也需要做對應的修改,不利于后期維護。
枚舉就是為了這樣的問題而誕生的。它們給出了將一個任意項同另一個項相比較的能力,并且可以在一個已定義項列表中進行迭代。枚舉(在Jave中簡稱為enum)是一個特定類型的類。所有枚舉都是Java中的新類java.lang.Enum的隱式子類。此類不能手工進行子類定義。一個簡單的枚舉可以是這樣:
[java] view plain copy
package com.fhp.enumexample; public enum TypeEnum { VIDEO, AUDIO, TEXT, IMAGE }上面的Entity類就可以改成這樣:
[java] view plain copy
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對象賦值的時候,就可以這樣:
[java] view plain copy
Entity e = new Entity(); e.setId(10); e.setType(TypeEnum.AUDIO);怎么看,都是好了很多。在調用setType()時,可選值只有四個,否則會出現編譯錯誤,因此可以看出,枚舉是類型安全的,不會出現取值范圍錯誤的問題。同時,客戶端不需要建立對枚舉中常量值的了解,使用起來很方便,并且可以容易地對枚舉進行修改,而無需修改客戶端。如果常量從枚舉中被刪除了,那么客戶端將會失敗并且將會收到一個錯誤消息。枚舉中的常量名稱可以被打印,因此除了僅僅得到列表中項的序號外還可以獲取更多信息。這也意味著常量可用作集合的名稱,例如HashMap。
因為在Java中一個枚舉就是一個類,它也可以有屬性和方法,并且實現接口。只是所有的枚舉都繼承自java.lang.Enum類,因此enum不可以再繼承其他的類。
下面給出在枚舉中聲明屬性和方法的示例:
[java] view plain copy
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數值。同時,它和普通的類一樣,可以聲明構造器和各種各樣的方法。如:
[java] view plain copy
TypeEnum type = TypeEnum.TEXT;//type的value屬性值為3。 System.out.println(type.getValue());//屏幕輸出3。如果要為每個枚舉值指定屬性,則在枚舉中必須聲明一個參數為屬性對應類型的構造方法(不能是public)。否則編譯器將給出The constructor TypeEnum(int, String) is undefined的錯誤。在此例中,屬性為int型,因此構造方法應當為int型。除此之外,還可以為枚舉指定多個屬性,如:
[java] view plain copy
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()
返回該枚舉的所有值。
現在,假設要為該枚舉實現一個根據整數值生成枚舉值的方法,可以這樣做:
[java] view plain copy
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 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中需要表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量,應當盡量舍棄常量表示的做法,而將枚舉作為首要的選擇。 ** Java 枚舉7常見種用法**
用法一:常量
在JDK1.5 之前,我們定義常量都是: publicstaticfianl.... 。現在好了,有了枚舉,可以把相關的常量分組到一個枚舉類型里,而且枚舉提供了比常量更多的方法。
Java代碼
public enum Color { RED, GREEN, BLANK, YELLOW }用法二:switch
JDK1.6之前的switch語句只支持int,char,enum類型,使用枚舉,能讓我們的代碼可讀性更強。
Java代碼
enum Signal { GREEN, YELLOW, RED } public class TrafficLight { Signal color = Signal.RED; public void change() { switch (color) { case RED: color = Signal.GREEN; break; case YELLOW: color = Signal.RED; break; case GREEN: color = Signal.YELLOW; break; } } }用法三:向枚舉中添加新方法
如果打算自定義自己的方法,那么必須在enum實例序列的最后添加一個分號。而且 Java 要求必須先定義 enum 實例。
Java代碼
public enum Color { RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4); // 成員變量 private String name; private int index; // 構造方法 private Color(String name, int index) { this.name = name; this.index = index; } // 普通方法 public static String getName(int index) { for (Color c : Color.values()) { if (c.getIndex() == index) { return c.name; } } return null; } // get set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } }用法四:覆蓋枚舉的方法
下面給出一個toString()方法覆蓋的例子。
Java代碼
public enum Color { RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4); // 成員變量 private String name; private int index; // 構造方法 private Color(String name, int index) { this.name = name; this.index = index; } //覆蓋方法 [@Override](https://my.oschina.net/u/1162528) public String toString() { return this.index+"_"+this.name; } }用法五:實現接口
所有的枚舉都繼承自java.lang.Enum類。由于Java 不支持多繼承,所以枚舉對象不能再繼承其他類。
Java代碼
public interface Behaviour { void print(); String getInfo(); } public enum Color implements Behaviour{ RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4); // 成員變量 private String name; private int index; // 構造方法 private Color(String name, int index) { this.name = name; this.index = index; } //接口方法 [@Override](https://my.oschina.net/u/1162528) public String getInfo() { return this.name; } //接口方法 [@Override](https://my.oschina.net/u/1162528) public void print() { System.out.println(this.index+":"+this.name); } }用法六:使用接口組織枚舉
Java代碼
public interface Food { enum Coffee implements Food{ BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO } enum Dessert implements Food{ FRUIT, CAKE, GELATO } }用法七:關于枚舉集合的使用
java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重復;EnumMap中的 key是enum類型,而value則可以是任意類型。關于這個兩個集合的使用就不在這里贅述,可以參考JDK文檔。
關于枚舉的實現細節和原理請參考:
參考資料:《ThinkingInJava》第四版
轉載于:https://my.oschina.net/sunhacker/blog/1587260
總結
以上是生活随笔為你收集整理的浅谈在Java开发中的枚举的作用和用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记一次坑爹的 “跨域” 问题
- 下一篇: Java中的各种O