C語言中文網 目錄

Java枚舉(enum)詳解:Java聲明枚舉類型、枚舉(enum)類、EnumMap 與 EnumSet

枚舉是一個被命名的整型常數的集合,用于聲明一組帶標識符的常數。枚舉在曰常生活中很常見,例如一個人的性別只能是“男”或者“女”,一周的星期只能是 7 天中的一個等。類似這種當一個變量有幾種固定可能的取值時,就可以將它定義為枚舉類型。

在 JDK 1.5 之前沒有枚舉類型,那時候一般用接口常量來替代。而使用 Java 枚舉類型 enum 可以更貼近地表示這種常量。

聲明枚舉

聲明枚舉時必須使用 enum 關鍵字,然后定義枚舉的名稱、可訪問性、基礎類型和成員等。枚舉聲明的語法如下:
enum-modifiers enum enumname:enum-base
{
    enum-body,
}

其中,enum-modifiers 表示枚舉的修飾符主要包括 public、private 和 internal;enumname 表示聲明的枚舉名稱;enum-base 表示基礎類型;enum-body 表示枚舉的成員,它是枚舉類型的命名常數。

任意兩個枚舉成員不能具有相同的名稱,且它的常數值必須在該枚舉的基礎類型的范圍之內,多個枚舉成員之間使用逗號分隔。

提示:如果沒有顯式地聲明基礎類型的枚舉,那么意味著它所對應的基礎類型是 int。

例 1

下面代碼定義了一個表示性別的枚舉類型 SexEnum 和一個表示顏色的枚舉類型 Color。
public enum SexEnum
{
    male,female;
}
public enum Color
{
    RED,BLUE,GREEN,BLACK;
}
之后便可以通過枚舉類型名直接引用常量,如 SexEnum.male、Color.RED。

使用枚舉還可以使 switch 語句的可讀性更強,例如以下示例代碼:
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;
        }
    }
}

枚舉類

Java 中的每一個枚舉都繼承自 java.lang.Enum 類。當定義一個枚舉類型時,每一個枚舉類型成員都可以看作是 Enum 類的實例,這些枚舉成員默認都被 final、public, static 修飾,當使用枚舉類型成員時,直接使用枚舉名稱調用成員即可。

所有枚舉實例都可以調用 Enum 類的方法,常用方法如表 1 所示。

表1 Enum類的常用方法
方法名稱 描述
values() 以數組形式返回枚舉類型的所有成員
valueOf() 將普通字符串轉換為枚舉實例
compareTo() 比較兩個枚舉成員在定義時的順序
ordinal() 獲取枚舉成員的索引位置

例 2

通過調用枚舉類型實例的 values() 方法可以將枚舉的所有成員以數組形式返回,也可以通過該方法獲取枚舉類型的成員。

下面的示例創建一個包含 3 個成員的枚舉類型 Signal,然后調用 values() 方法輸出這些成員。
enum Signal
{
    //定義一個枚舉類型
    GREEN,YELLOW,RED;
}
public static void main(String[] args)
{
    for(int i=0;i<Signal.values().length;i++)
    {
        System.out.println("枚舉成員:"+Signal.values()[i]);
    }
}

輸出結果如下:
枚舉成員:GREEN
枚舉成員:YELLOW
枚舉成員:RED

例 3

創建一個示例,調用 valueOf() 方法獲取枚舉的一個成員,再調用 compareTo() 方法進行比較,并輸出結果。具體實現代碼如下:
public class TestEnum
{
    public enum Sex
    {
        //定義一個枚舉
        male,female;
    }
    public static void main(String[] args)
    {
        compare(Sex.valueOf("male"));    //比較
    }
    public static void compare(Sex s)
    {
        for(int i=0;i<Sex.values().length;i++)
        {
            System.out.println(s+"與"+Sex.values()[i]+"的比較結果是:"+s.compareTo(Sex.values()[i]));
        }
    }
}

上述代碼中使用 Sex.valueOf("male") 取出枚舉成員 male 對應的值,再將該值與其他枚舉成員進行比較。最終輸出結果如下:
male與male的比較結果是:0
male與female的比較結果是:-1

例 4

通過調用枚舉類型實例的 ordinal() 方法可以獲取一個成員在枚舉中的索引位置。下面的示例創建一個包含 3 個成員的枚舉類型 Signal,然后調用 ordinal() 方法輸出成員及對應索引位置。

具體實現代碼如下:
public class TestEnum1
{
    enum Signal
    {
        //定義一個枚舉類型
        GREEN,YELLOW,RED;
    }
    public static void main(String[] args)
    {
        for(int i=0;i<Signal.values().length;i++)
        {
            System.out.println("索引"+Signal.values()[i].ordinal()+",值:"+Signal.values()[i]);
        }
    }
}

輸出結果如下:
索引0,值:GREEN
索引1,值:YELLOW
索引2,值:RED

為枚舉添加方法

Java 為枚舉類型提供了一些內置的方法,同時枚舉常量也可以有自己的方法。此時要注意必須在枚舉實例的最后一個成員后添加分號,而且必須先定義枚舉實例。

例 5

下面的代碼創建了一個枚舉類型 WeekDay,而且在該類型中添加了自定義的方法。
enum WeekDay
{
    Mon("Monday"),Tue("Tuesday"),Wed("Wednesday"),Thu("Thursday"),Fri("Friday"),Sat("Saturday"),Sun("Sunday");
    //以上是枚舉的成員,必須先定義,而且使用分號結束
    private final String day;
    private WeekDay(String day)
    {
        this.day=day;
    }
    public static void printDay(int i)
    {
        switch(i)
        {
            case 1:
                System.out.println(WeekDay.Mon);
                break;
            case 2:
                System.out.println(WeekDay.Tue);
                break;
            case 3:
                System.out.println(WeekDay.Wed);
                break;
            case 4:
                System.out.println(WeekDay.Thu);
                break;
            case 5:
                System.out.println(WeekDay.Fri);
                break;
            case 6:
                System.out.println(WeekDay.Sat);
                break;
            case 7:
                System.out.println(WeekDay.Sun);
                break;
            default:
                System.out.println("wrong number!");
        }
    }
    public String getDay()
    {
        return day;
    }
}

上面代碼創建了 WeekDay 枚舉類型,下面遍歷該枚舉中的所有成員,并調用 printDay() 方法。示例代碼如下:
public static void main(String[] args)
{
    for(WeekDay day:WeekDay.values())
    {
        System.out.println(day+"====>"+day.getDay());
    }
    WeekDay.printDay(5);
}

輸出結果如下:
Mon====>Monday
Tue====>Tuesday
Wed====>Wednesday
Thu====>Thursday
Fri====>Friday
Sat====>Saturday
Sun====>Sunday
Fri

Java 中的 enum 還可以跟 Class 類一樣覆蓋基類的方法。下面示例代碼創建的 Color 枚舉類型覆蓋了 toString() 方法。
public class Test
{
    public enum Color
    {
        RED("紅色",1),GREEN("綠色",2),WHITE("白色",3),YELLOW("黃色",4);
        //成員變量
        private String name;
        private int index;
        //構造方法
        private Color(String name,int index)
        {
            this.name=name;
            this.index=index;
        }
        //覆蓋方法
        @Override
        public String toString()
        {
            return this.index+"-"+this.name;
        }
    }
    public static void main(String[] args)
    {
        System.out.println(Color.RED.toString());    //輸出:1-紅色
    }
}

EnumMap 與 EnumSet

為了更好地支持枚舉類型,java.util 中添加了兩個新類:EnumMapEnumSet。使用它們可以更高效地操作枚舉類型。

EnumMap 類

EnumMap 是專門為枚舉類型量身定做的 Map 實現。雖然使用其他的 Map(如 HashMap)實現也能完成枚舉類型實例到值的映射,但是使用 EnumMap 會更加高效。

HashMap 只能接收同一枚舉類型的實例作為鍵值,并且由于枚舉類型實例的數量相對固定并且有限,所以 EnumMap 使用數組來存放與枚舉類型對應的值,使得 EnumMap 的效率非常高。

例 6

下面是使用 EnumMap 的一個代碼示例。枚舉類型 DataBaseType 里存放了現在支持的所有數據庫類型。針對不同的數據庫,一些數據庫相關的方法需要返回不一樣的值,例如示例中 getURL() 方法。
//定義數據庫類型枚舉
public enum DataBaseType
{
    MYSQUORACLE,DB2,SQLSERVER
}
//某類中定義的獲取數據庫URL的方法以及EnumMap的聲明
private EnumMap<DataBaseType,String>urls=new EnumMap<DataBaseType,String>(DataBaseType.class);
public DataBaseInfo()
{
    urls.put(DataBaseType.DB2,"jdbc:db2://localhost:5000/sample");
    urls.put(DataBaseType.MYSQL,"jdbc:mysql://localhost/mydb");
    urls.put(DataBaseType.ORACLE,"jdbc:oracle:thin:@localhost:1521:sample");
    urls.put(DataBaseType.SQLSERVER,"jdbc:microsoft:sqlserver://sql:1433;Database=mydb");
}
//根據不同的數據庫類型,返回對應的URL
//@param type DataBaseType 枚舉類新實例
//@return
public String getURL(DataBaseType type)
{
    return this.urls.get(type);
}

在實際使用中,EnumMap 對象 urls 往往是由外部負責整個應用初始化的代碼來填充的。這里為了演示方便,類自己做了內容填充。

從本例中可以看出,使用 EnumMap 可以很方便地為枚舉類型在不同的環境中綁定到不同的值上。本例子中 getURL 綁定到 URL 上,在其他的代碼中可能又被綁定到數據庫驅動上去。

EnumSet 類

EnumSet 是枚舉類型的高性能 Set 實現,它要求放入它的枚舉常量必須屬于同一枚舉類型。EnumSet 提供了許多工廠方法以便于初始化,如表 2 所示。

表2 EnumSet 類的常用方法
方法名稱 描述
allOf(Class<E> element type) 創建一個包含指定枚舉類型中所有枚舉成員的 EnumSet 對象
complementOf(EnumSet<E> s) 創建一個與指定 EnumSet 對象 s 相同的枚舉類型 EnumSet 對象,
并包含所有 s 中未包含的枚舉成員
copyOf(EnumSet<E> s) 創建一個與指定 EnumSet 對象 s 相同的枚舉類型 EnumSet 對象,
并與 s 包含相同的枚舉成員
noneOf(<Class<E> elementType) 創建指定枚舉類型的空 EnumSet 對象
of(E first,e...rest) 創建包含指定枚舉成員的 EnumSet 對象
range(E from ,E to) 創建一個 EnumSet 對象,該對象包含了 from 到 to 之間的所有枚
舉成員

EnumSet 作為 Set 接口實現,它支持對包含的枚舉常量的遍歷。
for(Operation op:EnumSet.range(Operation.PLUS,Operation.MULTIPLY))
{
    doSomeThing(op);
}

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo