列舉類的使用和理解enmu
原始的介面定義常量
String SAT = "Sat" ;
|
語法(定義)
建立列舉型別要使用 enum 關鍵字,隱含了所建立的型別都是 java.lang.Enum 類的子類(java.lang.Enum 是一個抽象類)。列舉型別符合通用模式 Class Enum<E extends Enum<E>>
,而 E
表示列舉型別的名稱。列舉型別的每一個值都將對映到 protected Enum(String name, int ordinal)
|
這段程式碼實際上呼叫了7次 Enum(String name, int ordinal):
"MON" , 0 );
|
遍歷、switch 等常用操作
對enum進行遍歷和switch的操作示例程式碼:
|
輸出結果:
|
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)
反編譯解析:
public
enum
ColorEnum {
RED,BLUE,GREEN
}
通過工具解析class後獲得的原始碼(
public final class ColorEnum extends Enum { //返回儲存列舉例項的陣列的副本。values()方法通常用於foreach迴圈遍歷列舉常量。 public static ColorEnum[] values() { return (ColorEnum[])$VALUES.clone(); } //根據例項名獲取例項 public static ColorEnum valueOf(String s) { return (ColorEnum)Enum.valueOf(ColorEnum, s); } //私有構造方法,這裡呼叫了父類的構造方法,其中引數s對應了常量名,引數i代表列舉的一個順序(這個順序與列舉的宣告順序對應,用於oridinal()方法返回順序值) private ColorEnum(String s, int i) { super(s, i); } //我們定義的列舉在這裡聲明瞭三個 ColorEnum的常量物件引用,物件的例項化在static靜態塊中 public static final ColorEnum RED; public static final ColorEnum BLUE; public static final ColorEnum GREEN; //將所有列舉的例項存放在陣列中 private static final ColorEnum $VALUES[]; static { RED = new ColorEnum("RED", 0); BLUE = new ColorEnum("BLUE", 1); GREEN = new ColorEnum("GREEN", 2); //將所有列舉的例項存放在陣列中 $VALUES = (new ColorEnum[] { RED, BLUE, GREEN }); } }
給 enum 自定義屬性和方法
public enum ColorEnum { RED("red","紅色"),GREEN("green","綠色"),BLUE("blue","藍色"); //防止欄位值被修改,增加的欄位也統一final表示常量 private final String key; private final String value; private ColorEnum(String key,String value){ this.key = key; this.value = value; } //根據key獲取列舉 public static ColorEnum getEnumByKey(String key){ if(null == key){ return null; } for(ColorEnum temp:ColorEnum.values()){ if(temp.getKey().equals(key)){ return temp; } } return null; } public String getKey() { return key; } public String getValue() { return value; } } 反編譯結果: public final class ColorEnum extends Enum { public static ColorEnum[] values() { return (ColorEnum[])$VALUES.clone(); } public static ColorEnum valueOf(String s) { return (ColorEnum)Enum.valueOf(ColorEnum, s); } //構造方法在原基礎上加上我們新增的兩個形參 private ColorEnum(String s, int i, String s1, String s2) { super(s, i); key = s1; value = s2; } //自定義方法,通過key值獲得對應的列舉物件 public static ColorEnum getEnumByKey(String s) { if(null == s) return null; ColorEnum acolorenum[] = values(); int i = acolorenum.length; for(int j = 0; j < i; j++) { ColorEnum colorenum = acolorenum[j]; if(colorenum.getKey().equals(s)) return colorenum; } return null; } public String getKey() { return key; } public String getValue() { return value; } public static final ColorEnum RED; public static final ColorEnum GREEN; public static final ColorEnum BLUE; //我們自定義的兩個欄位 private final String key; private final String value; private static final ColorEnum $VALUES[]; static { RED = new ColorEnum("RED", 0, "red", "\u7EFE\u3223\u58CA"); GREEN = new ColorEnum("GREEN", 1, "green", "\u7F01\u80EF\u58CA"); BLUE = new ColorEnum("BLUE", 2, "blue", "\u9483\u6FCA\u58CA"); $VALUES = (new ColorEnum[] { RED, GREEN, BLUE }); } EnumSet,EnumMap 的應用
|
原理分析
enum 的語法結構儘管和 class 的語法不一樣,但是經過編譯器編譯之後產生的是一個class檔案。該class檔案經過反編譯可以看到實際上是生成了一個類,該類繼承了java.lang.Enum<E>。EnumTest 經過反編譯(javap com.hmw.test.EnumTest 命令)之後得到的內容如下:
|
所以,實際上 enum 就是一個 class,只不過 java 編譯器幫我們做了語法的解析和編譯而已。
總結
1、轉變觀念
最重要的是把enum看成和class和interface同等地位就好很容易理解EnumSet和EnumMap。
可以把 enum 看成是一個普通的 class,它們都可以定義一些屬性和方法,不同之處是:enum 不能使用 extends 關鍵字繼承其他類,因為 enum 已經繼承了 java.lang.Enum(java是單一繼承)
2.列舉的好處以及與常量類的區別
1)列舉型可以直接與資料庫打交道,我通常使用varchar型別儲存,對應的是列舉的常量名。(資料庫中好像也有列舉型別,不過也沒用過)
2) switch語句支援列舉型,當switch使用int、String型別時,由於值的不穩定性往往會有越界的現象,對於這個的處理往往只能通過if條件篩選以及default模組來處理。而使用列舉型後,在編譯期間限定型別,不允許發生越界的情況
3) 當你使用常量類時,往往得通過equals去判斷兩者是否相等,使用列舉的話由於常量值地址唯一,可以用==直接對比,效能會有提高
4) 常量類編譯時,是直接把常量的值編譯到類的二進位制程式碼裡,常量的值在升級中變化後,需要重新編譯引用常量的類,因為裡面存的是舊值。列舉類編譯時,沒有把常量值編譯到程式碼裡,即使常量的值發生變化,也不會影響引用常量的類。
5)列舉類編譯後預設為final class,不允許繼承可防止被子類修改。常量類可被繼承修改、增加欄位等,容易導致父類的不相容。
總結:常量的定義在開發中是必不可少的,雖然無論是通過常量類定義常量還是列舉定義常量都可以滿足常量定義的需求。但個人建議最好是使用列舉型別。