文章目錄
深入理解枚舉類
簡介
enum
全稱是 enumeration,是 JDK1.5 引入的新特性,位於Java.lang
包下。
在Java中 enum
是一個關鍵字,被 enum
修飾的類型就是枚舉類。
public enum ColorEnum{
BLACK,WHITE,GREEN;
}
枚舉的好處
將枚舉類型用作set或map的類型時,專用且高效。(引自枚舉類的介紹)
枚舉的典型應用
如 狀態碼、常量、顏色、類別等
使用規範
- 枚舉類名帶上Enum後綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。
正例:枚舉名字爲ProcessStatusEnum的成員名稱:SUCCESS / UNKNOWN_REASON - 所有的枚舉類型字段必須要有註釋,說明每個數據項的用途
引自阿里巴巴開發手冊
枚舉的本質
枚舉類的聲明
package java.lang;
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
}
下面我們新建一個枚舉類`ColorEnum``
public enum ColorEnum{
BLACK,WHITE,GREEN;
}
- 執行
javac ColorEnum.java
命令,生成ColorEnum.class
文件. - 接着執行
javap ColorEnum.class
命令,輸入如下內容:
public final class com.sun.advanced.learnenum.ColorEnum extends java.lang.Enum<com.sun.advanced.learnenum.ColorEnum> {
public static final com.sun.advanced.learnenum.ColorEnum BLACK;
public static final com.sun.advanced.learnenum.ColorEnum WHITE;
public static final com.sun.advanced.learnenum.ColorEnum GREEN;
public static com.sun.advanced.learnenum.ColorEnum[] values();
public static com.sun.advanced.learnenum.ColorEnum valueOf(java.lang.String);
static {};
}
從上面可以看出,枚舉的本質是
java.lang.Enum
的子類。
儘管enum
看起來很像一種新的數據類型,但實際上,enum是一種受限制的類,並且有自己的方法。
枚舉類被修飾爲final
,所以不能被其他類所繼承。
定義的枚舉值被修飾爲static final
,本質上枚舉值就是一種靜態常量
枚舉其實就是特殊的類,域成員均爲常量,且構造方法被默認強制是私有。–阿里巴巴開發手冊
枚舉的方法
String name()
: 返回此枚舉常量的名稱int ordinal()
: 此枚舉常量的序號(它在枚舉聲明中的位置,其中初始常量的序數爲零)。String toString
: 返回枚舉常量名boolean equals(Object other)
: 判斷是否爲同一個對象Class<E> getDeclaringClass()
: 返回實例所屬的 enum 類型static <T extends Enum<T>> T valueOf valueOf(Class<T> enumType String name)
: 返回指定名字、給定類的枚舉常量- int compareTo(E other): 如果枚舉常量出現在other之前,則返回用一個負值;如果this==other,則返回0;否則,返回正值。枚舉常量的出現次數在enum中給出
可以使用==
來比較enum實例
enum
的基本方法:
public class EnumMethodDemo {
public static void main(String[] args) {
System.out.println("******************Print all color**************");
for (ColorEnum colorEnum : ColorEnum.values()) {
System.out.println(colorEnum + " ordinal " + colorEnum.ordinal());
}
System.out.println("******************Print method**************");
ColorEnum black = ColorEnum.BLACK;
System.out.println("black.name(): " + black.name());
System.out.println("black.getDeclaringClass(): " + black.getDeclaringClass());
System.out.println("black.hashCode(): " + black.hashCode());
System.out.println("black.compareTo(ColorEnum.BLACK): " + black.compareTo(ColorEnum.BLACK));
System.out.println("black.equals(ColorEnum.BLACK): " + black.equals(ColorEnum.BLACK));
System.out.println("black.equals(ColorEnum.WHITE): " + black.equals(ColorEnum.WHITE));
System.out.format("black == ColorEnum.WHITE", black == ColorEnum.WHITE);
}
}
輸出
******************Print all color**************
BLACK ordinal 0
WHITE ordinal 1
GREEN ordinal 2
******************Print method**************
black.name(): BLACK
black.getDeclaringClass(): class com.sun.advanced.learnenum.ColorEnum
black.hashCode(): 1956725890
black.compareTo(ColorEnum.BLACK): 0
black.equals(ColorEnum.BLACK): true
black.equals(ColorEnum.WHITE): false
black == ColorEnum.WHITE
Process finished with exit code 0
枚舉的特性
基本特性
如果枚舉中沒有定義方法,也可以在最後一個實例後面加逗號、分號或什麼都不加
枚舉可以添加方法
枚舉值認爲從0開始的有序數值。
枚舉可以添加普通方法、靜態方法、抽象方法、構造方法
Java中不允許使用=
爲枚舉常量賦值。而是添加方法來間接實現顯示賦值。
枚舉可以實現接口
public interface INumberEnum {
int getCode();
String getDescription();
}
public enum ErrorCodeEnum implements INumberEnum {
OK(0,"成功"),
ERROR_A(100,"錯誤A"),
ERROR_B(200,"錯誤B");
private int code;
private String description;
ErrorCodeEnum(int number, String description) {
this.code = number;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
枚舉的應用
組織常量
以前,在Java中定義常量都是public static final T A;
這樣的形式。有了枚舉類,你可以將有關聯關係的常量組織起來,使代碼更加易讀、安全,並且還可以使用枚舉提供的方法
狀態機
我們經常使用switch語句來寫狀態機。JDK1.7以後,switch已經支持int、
char、
string、
enum`類型的參數。這幾種類型的參數比較起來,使用枚舉的switch更具有可讀性
public enum StateEnum {
GREEN,
YYELLOW,
RED;
}
public class StateMachineDemo {
public static void main(String[] args) {
System.out.println(getTrafficInstruct(StateEnum.RED));
}
public static String getTrafficInstruct(StateEnum singal){
String instruct = "信號燈故障";
switch (singal){
case RED:
instruct="紅燈停";
break;
case GREEN:
instruct="黃燈請注意";
break;
case YYELLOW:
instruct="綠燈行";
break;
default:
break;
}
return instruct;
}
}
輸出
紅燈停
錯誤碼
枚舉常常用於定義程序錯誤碼。下面使一個簡單示例
public enum HttpStatusEnum {
OK(200,"成功"),
NOT_FOUND(404,"資源未找到");
private int code;
private String msg;
HttpStatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
@Override
public String toString() {
return super.toString();
}
}
public class HttpStateDemo {
public static void main(String[] args) {
for (HttpStatusEnum value : HttpStatusEnum.values()) {
System.out.println(value.getCode() +" "+ value.toString());
}
}
}
組織枚舉
可以將類型接近的枚舉通過接口或類組織起來來,但是一般用接口的方式進行組織。
原因是:Java接口在編譯時會自動爲enum類型加上public static
修飾符;Java類編譯時會自動爲enum
類型加上static修飾符,就是說,在類組織enum
,如果你不給他修飾爲public,那麼之惡能在本包中進行訪問
在一個接口的內部,創建實現該接口的枚舉,以此將元素進行分組,可以達到將枚舉元素分類組織的目的。舉例來說,假設你想用enum來表示不同類別的食物,同時還希望每個enum元素仍然保持Food類型,那麼可以這樣實現:
public interface Food {
enum Appetizer implements Food{
SALAD,SOUP,SPRING_ROLLS;
}
enum MainCourse implements Food{
LASAGNE,BURRITO,PAD_THAI,
LENTILS,HUMMOUS,VINDALOO;
}
enum Dessert implements Food{
TIRAMISU,GELATO,FRUIT;
}
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,ESPRESSO,
LATTE,CAPPUCCINO,TEA,HERB_TEA;
}
}
這些枚舉都實現了Food接口,所以可以利用Food對具體實例進行實例化
import static com.sun.advanced.learnenum.Food.*;
public class TypeOfFood {
public static void main(String[] args) {
Food food = Appetizer.SALAD;
food = MainCourse.LASAGNE;
food = Dessert.GELATO;
food = Coffee.BLACK_COFFEE;
}
}
枚舉工具類
Java 中提供了兩個方便操作enum的工具類EnumSet
,EnumMap
EnumSet
Set
是一種集合,只能向其中添加不重複的對象。當然enum也要求成員都是唯一的,所以enum看起來也具有集合的行爲。EnumSet
是枚舉類型的高性能Set
實現。它要求放入它的枚舉常量必須屬於同一枚舉類型
主要接口:
- noneOf:創建一個具有指定元素類型的空EnumSet
- allOf:創建一個指定元素類型幷包含所有枚舉值的EnumSet
- range: 創建一個包括枚舉值中指定範圍元素的EnumSet
- complenmentsOf:初始化集合包括指定集合的補集
- of:創建一個包括參數中所有元素的EnumSet
- copyOf:創建一個包含參數容器的所有元素的EnumSet
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<HttpStatusEnum> httpStatusEnums = EnumSet.allOf(HttpStatusEnum.class);
for (HttpStatusEnum value : httpStatusEnums) {
System.out.println(value.name());
}
}
}
EnumMap
EnumMap
是一種特殊的Map,它要求其中的key必須來自一個enum
。由於enum本身的限制,所以EnumMap在內部可由數組實現。因此EnumMap的速度很快,我們可以放心的使用enum實例在EnumMap中進行查找操作。不過我們只能將enum的實例作爲key來調用put()方法,其他操作與使用一般的Map差不多。
public class EnumMapDemo {
public static void main(String[] args) {
EnumMap enumMap = new EnumMap(StateEnum.class);
enumMap.put(StateEnum.RED,"紅燈");
enumMap.put(StateEnum.GREEN,"綠燈");
enumMap.put(StateEnum.YYELLOW,"黃燈");
for (Object o : enumMap.entrySet()) {
System.out.println(o);
}
}
}
參考資料
- Java編程思想
- 深入理解Java枚舉類
- 阿里巴巴開發手冊