淺談 Java 中的枚舉

來源:互聯網
上載者:User

枚舉也就是一一列舉,常用來表示那些可以明確範圍的集合,比方說性別,季節,星期,月份等。

 

在 JDK 1.5 才出現枚舉類,在沒有出現枚舉類之前,我們要表示幾個確定的值通常會使用常量來表示,形如

 

    public static final Integer SPRING = 1;    public static final Integer SUMMER = 2;    public static final Integer FALL = 3;    public static final Integer WINTER = 4;

 

我們可以使用枚舉類來表示,這也就是最簡單的枚舉。

 

enum Season{    SPRING,SUMMER,FALL,WINTER;}

 

那麼枚舉類和定義常量相比有什麼優勢呢?

 

安全,我們看上面的代碼可以知道,使用常量表示的季節都是 Integer 類型的,而這個類型的資料範圍太大了,而使用枚舉就限制了資料的域。枚舉可以理解為幾個常量的集合,資料不太會改變,使用枚舉之後語義更加明確,因為資料域不大。

 

關於枚舉類,有幾點需要注意:

 

  1. enum 和 class ,interface 的地位一樣

  2. 使用 enum 定義的枚舉類預設繼承了 java.lang.Enum,而不是繼承 Object 類。枚舉類可以實現一個或多個介面,不能再繼承其他類了。

  3. 枚舉類的所有執行個體都必須放在第一行展示,不需使用 new 關鍵字,不需顯式調用構造器。自動添加 public static final 修飾。

  4. 枚舉類的構造器只能是私人的。

 

關於第 4 點,我要說枚舉類的定義是單例模式的,單例模式要求構造器私人化,不允許在外部建立新的對象,你想呀,枚舉類的作用就是準確的表示出同一類別下的不同資料。在我們定義的時候已經建立好了,所以跟本不需要也不能在外部繼續建立新的對象。故,需要將構造器私人化。

 

枚舉類說的通俗點就是被閹割的類,我們使用類可以建立對象,而枚舉類在定義的時候就會指定建立的對象有哪些。你沒有顯示的寫代碼建立,不過是由於 JVM 自動給你加上去了。待會看看枚舉類被反編譯之後的情況就會理解。

 

枚舉類中可以定義屬性和方法。

 

enum Season{    SPRING("春天","一年之計在於春"),SUMMER("夏天","夏天好熱 ~ "),    FALL("秋天","秋水共長天一色"),WINTER("冬天","冬天好冷 ~ ");    // 添加枚舉對象的名稱    private final String name;    // 添加枚舉對象的描述    private final String desc;    private Season(String name,String desc){        this.name = name;        this.desc = desc;    }    public String getName(){        return name;    }    public String getDesc(){        return desc;    }}

 

我們可以看到,有一個帶參的私人建構函式,所以在定義枚舉的時候可以直接賦值,而調用建立對象是由虛擬機器自動完成的,還可以添加更多的屬性,我們可以正常使用枚舉對象。

 

// 擷取所有的枚舉對象,返回的是數組Season[] values = Season.values();for (Season season : values) {System.out.println(season.getName() + " : " + season.getDesc());}春天 : 一年之計在於春夏天 : 夏天好熱 ~ 秋天 : 秋水共長天一色冬天 : 冬天好冷 ~

 

枚舉類中實現抽象方法

 

這肯定有點迷糊,我們知道含有抽象方法的類是抽象類別,那為什麼枚舉類不是 abstract 的也可以含有抽象方法呢 ?我們先來看看實現,待會說原因。

 

enum Season{    SPRING("春天","一年之計在於春") {        @Override        public Season getNextSeason() {            return Season.valueOf("SUMMER");        }    },SUMMER("夏天","夏天好熱 ~ ") {        @Override        public Season getNextSeason() {            return Season.valueOf("FALL");        }    },        ... 省略        ... 省略        ... 省略    // 定義了一個抽象方法,擷取下一個季節    public abstract Season getNextSeason();}

測試代碼如下

 

public static void main(String[] args) {    String name = Season.SPRING.getNextSeason().getName();    System.out.println(name); // 夏天}

 

是不是有種似懂非懂的感覺,沒關係,我們來反編譯看一看枚舉類的內部構造你就會明白。

 

舉個簡單的例子來看一看枚舉類的原理。就拿一個最簡單的枚舉來說明情況。

 

public enum SeasonEnum {    SPRING,SUMMER,FALL,WINTER;}

 

看一看反編譯之後的代碼,我使用的反編譯工具是 jad 。

 

public final class SeasonEnum extends Enum{    public static SeasonEnum[] values()    {        return (SeasonEnum[])$VALUES.clone();    }    public static SeasonEnum valueOf(String s)    {        return (SeasonEnum)Enum.valueOf(SeasonEnum, s);    }    private SeasonEnum(String s, int i)    {        super(s, i);    }    public static final SeasonEnum SPRING;    public static final SeasonEnum SUMMER;    public static final SeasonEnum FALL;    public static final SeasonEnum WINTER;    private static final SeasonEnum $VALUES[];    static     {        SPRING = new SeasonEnum("SPRING", 0);        SUMMER = new SeasonEnum("SUMMER", 1);        FALL = new SeasonEnum("FALL", 2);        WINTER = new SeasonEnum("WINTER", 3);        $VALUES = (new SeasonEnum[] {            SPRING, SUMMER, FALL, WINTER        });    }}

 

可以看到枚舉類本質上就是一個繼承了 Enum 的一個單例最終類,而我們定義的枚舉對象也是在靜態代碼塊中初始化了,同時我們也可以看到 values 方法的實現就是返回執行個體對象的數組,也就是枚舉對象的數組,valueOf 方法接收一個字串,返回的是字串對應的枚舉對象,若是找不到,會報錯。

 

看到這我們也就能理解為什麼我們可以在枚舉類中定義抽象方法了,我們使用內部類實現了抽象方法,對應的每個對象在建立時都會實現相應的抽象方法。同樣的道理,枚舉類也可以實現介面,這裡就不示範了。

 

說了這麼多,也知道了枚舉的好處,但是不得不說的是我在實際的項目中,枚舉類的使用還真不多,下面就看看枚舉類可以有哪些用處,以後有這種需求就可以考慮使用枚舉來實現。

 

switch 語句支援枚舉類型是從 JDK 1.5 才開始的,因為此時才有枚舉這個特性。我們看一看具體的使用。

 

/** * 伺服器響應碼 */public enum ResponseCode {    SUCCESS(200,"訪問成功"),FAIL(404,"頁面不存在"),ERROR(500,"伺服器內部錯誤");    private Integer num;    private String desc;    private ResponseCode(Integer num,String desc){        this.num = num;        this.desc = desc;    }    public Integer getNum() {        return num;    }    public String getDesc() {        return desc;    }    /*     * 通過返回碼得到枚舉對象     */    public static ResponseCode getByNum(Integer num){        for(ResponseCode code : values()){            if(code.getNum().equals(num)){                return code;            }        }        return null;    }}=============測試=====================    public static void main(String[] args) {        ResponseCode code = ResponseCode.getByNum(200);        switch (code) {        case SUCCESS:            System.out.println("成功");            break;        default:            break;        }    }

 

在我做過的項目中,只有一處用到過枚舉,用來記錄字典的值,比方說,我寫一個工具類,記錄項目中使用到的所有字典相關資料。形如這樣

 

public class Keys {    enum Sex{        MALE,FEMALE;    }    enum State{        SUCCESS,FAIL;    }    enum Month{     }    enum Week{          }    public static void main(String[] args) {        Keys.Sex.MALE.name();    }}

 

但是在後面發現,還有更好用的配置字典的方式,建立一個字典類,將所有的字典資料放在一張表中,我們使用字典類來操作,這樣要比上面使用枚舉要好。

相關文章

Alibaba Cloud 10 Year Anniversary

With You, We are Shaping a Digital World, 2009-2019

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。