[java]話說枚舉

來源:互聯網
上載者:User

  程式中經常會使用到一些常數,如果這些常數是共用的,在java中可以定義一個類或介面來統一管理常數。其他對象從這些類或介面取用常數。如果需要修改常數則可以從這些類或介面上直接修改,而不用更改程式的其他部分。

  使用介面儲存常數:

public interface Usual {public static final int TURN_LEFT=1;public static final int TURN_RIGHT=2;public static final int SHOT=3;}

    在使用類儲存常數時,直接在類中進行定義即可

public class Action{              public static final  int  TURN_LEFT=1;              ..............................}

對於簡單的常數設定,以上兩種方法已經夠用了。在DK.1.5引用了枚舉類型,帶來了極大的方便

  1 簡單的常數設定

       2 獲得編譯時間類型檢查

       3 增強代碼的可讀性

 枚舉類型的性質:

  1. 定義枚舉類型其實就是在定義一個類,很多細節是由編譯器搞定,所以從某種程度上,enum關鍵字的作用可以看作是interface和class
  2. 使用enum定義枚舉類型時,定義出的類型是繼承自java.lang.Enum類,而每個被枚舉的成員其實就是定義的枚舉類型的一個執行個體,他們都預設為final,無法改變常數名設定的值,它們也是public和static的成員,可以通過類名稱直接使用它們。
  3. 枚舉類型的建構函式不得是public和protected的建構函式,這是為了避免粗心的開發人員直接對枚舉類型進行執行個體化
  4. 因值而異的類實現方式
  5. Enum覆蓋了toString方法,預設返回字串本身
  6. Enum提供了valueOf方法,這個方法和toString方法是相對應的,調用valueOf("name")將會返回enum.name,因此我們在重寫toString方法的時候要注意到這一點,一般來說應該相對應的重寫valueOf方法

 枚舉類型的方法

  1. values()方法:取得所有的枚舉成員執行個體,並以數組方式返回
  2. ordinal()方法:依枚舉順序得到位置索引,預設從0開始

  執行個體示範:

1 獲得編譯類型檢查

定義一個介面

public interface Usual {public static final int TURN_LEFT=1;public static final int TURN_RIGHT=2;public static final int SHOT=3;}

 

public static void main(String[] args) throws IOException{doAction(Action.TURN_LEFT);}public  static void doAction(int action){switch(action){case Usual.TURN_LEFT:System.out.println("向左走");break;case Usual.TURN_RIGHT:System.out.println("向右走");break;case Usual.SHOT:System.out.println("射擊");break;}return;}

   這種做法本身是沒錯的,但是doAction方法接受的是int類型的常數,我們是沒有能力阻止開發人員對其輸入規定外的常數,也沒有檢查switch中枚舉的值是不是正確的,因為參數action這是int類型而已,當然可以自行設計一些檢查動作,這需要一些額外的工作。而枚舉可以輕易的解決這些問題

定義一個枚舉類

public enum Action {TURN_LEFT,TURN_RIGHT,SHOT;public String get(){switch(this.ordinal()){case 0:return "向右轉";case 1:return "向左轉";case 2:return "射擊";default:return null;}}}

 

public static void main(String[] args) throws IOException{doAction(Action.TURN_LEFT);}public  static void doAction(Action action){switch(action){case TURN_LEFT:System.out.println("向左走");break;case TURN_RIGHT:System.out.println("向右走");break;case SHOT:System.out.println("射擊");break;}return;}

 這裡doAction的參數類型是Action,如果對方法輸入其他類型的變數,編譯器就會報告錯誤。

 使用枚舉類型還可以做進一步的檢查,如果在switch中加入了不屬於Action中枚舉的值,編譯器也會報告錯誤

public  static void doAction(Action action){switch(action){case TURN_LEFT:System.out.println("向左走");break;case TURN_RIGHT:System.out.println("向右走");break;case SHOT:System.out.println("射擊");break;}case STOP:System.out.println("停止");break;return;}

 這是編譯器會顯示錯誤:unqualified enumeration constant name required

              case STOP:

            ^

2 枚舉執行個體的簡單應用

下面這段代碼我是從http://www.cnblogs.com/linjiqin/archive/2011/02/11/1951632.html借鑒而來並做了很大的修改【自己想偷懶些】

/** * 枚舉用法詳解 */public class TestEnum {    /**     * 普通枚舉     */    public enum ColorEnum {        red, green, yellow, blue;        public static int length(){        return ColorEnum.values().length;        }//定義取得枚舉成員的個數即長度    }        public enum SeasonEnum {        //註:枚舉寫在最前面,否則編譯出錯        spring, summer, autumn, winter;        private final static String position = "test";        public static SeasonEnum getSeason() {            if ("test".equals(position))                return spring;            else                return winter;        }    }        /**     * 性別     *      * 實現帶有構造器的枚舉     */    public enum Gender{        //通過括弧賦值,而且必須帶有一個參構造器和一個屬性跟方法,否則編譯出錯        //賦值必須都賦值或都不賦值,不能一部分賦值一部分不賦值;如果不賦值則不能寫構造器,賦值編譯也出錯        MAN("MAN"), WOMEN("WOMEN");            private final String value;        //構造器預設也只能是private, 從而保證建構函式只能在內部使用        Gender(String value) {            this.value = value;        }             public String getValue() {            return value;        }    }       /**    *     * 實現帶有抽象方法的枚舉    */    public enum OrderState {        /** 已取消 */        CANCEL {public String getName(){return "已取消";}},        /** 待審核 */        WAITCONFIRM {public String getName(){return "待審核";}},        /** 等待付款 */        WAITPAYMENT {public String getName(){return "等待付款";}},        /** 正在配貨 */        ADMEASUREPRODUCT {public String getName(){return "正在配貨";}},        /** 等待發貨 */        WAITDELIVER {public String getName(){return "等待發貨";}},        /** 已發貨 */        DELIVERED {public String getName(){return "已發貨";}},        /** 已收貨 */        RECEIVED {public String getName(){return "已收貨";}};           public abstract String getName();//這裡是很重要的    }           public static void compareToSeasonEnum(SeasonEnum inputseasonenum){    System.out.println("請輸入"+inputseasonenum);    for(SeasonEnum el:SeasonEnum.values()){    System.out.println(el.compareTo(inputseasonenum));    }    }//比較SeasonEnum枚舉對象間的順序        public static void main(String[] args) {    System.out.println("===============================");        ColorEnum colorEnum = ColorEnum.blue;        switch (colorEnum) {        case red:            System.out.println("color is red");            break;        case green:            System.out.println("color is green");            break;        case yellow:            System.out.println("color is yellow");            break;        case blue:            System.out.println("color is blue");            break;        }        System.out.println("===============================\n\n");                        System.out.println("=====遍曆ColorEnum枚舉中的值====");        for(ColorEnum color : ColorEnum.values()){            System.out.println(color);        }        System.out.println("===============================\n\n");                System.out.println("====ColorEnum枚舉中的值有"+ColorEnum.length()+"個====");        System.out.println(ColorEnum.red.ordinal());//0        System.out.println(ColorEnum.green.ordinal());//1        System.out.println(ColorEnum.yellow.ordinal());//2        System.out.println(ColorEnum.blue.ordinal());//3        System.out.println(ColorEnum.red.compareTo(ColorEnum.green));//-1        System.out.println("===============================\n\n");                System.out.println("===============================");        System.out.println("季節為" + SeasonEnum.getSeason());        System.out.println("===============================\n\n");                        System.out.println("===============================");            for(Gender gender : Gender.values()){            System.out.println(gender.value);        }        System.out.println("===============================\n\n");                System.out.println("===============================");        for(OrderState order : OrderState.values()){            System.out.println(order.getName());        }        System.out.println("===============================\n\n");                        System.out.println("========valueOf方法應用========");        //靜態valueOf方法可以讓指定的字串嘗試轉換為枚舉執行個體        compareToSeasonEnum(SeasonEnum.valueOf("winter"));        System.out.println("===============================\n\n");      
        System.out.println("******EnumSet的用法********");  
        // EnumSet的使用 
        EnumSet<ColorEnum> stateSet = EnumSet.allOf(ColorEnum.class); 
        for (ColorEnum s : stateSet) { 
            System.out.println(s); 
        } 

 

System.out.println("******EnumSet的用法********");          // EnumSet的使用          EnumSet<ColorEnum> stateSet = EnumSet.allOf(ColorEnum.class);          for (ColorEnum s : stateSet) {              System.out.println(s);          }                    System.out.println("******EnumMap的用法********");          //EnumMap的使用          EnumMap stateMap = new EnumMap(ColorEnum.class);          stateMap.put(ColorEnum.red, "is red");          stateMap.put(ColorEnum.green, "is green");          stateMap.put(ColorEnum.yellow, "is yellow");         stateMap.put(ColorEnum.blue, "is blue");         for (ColorEnum s : ColorEnum.values()) {              System.out.println(s.name() + ":" + stateMap.get(s));          }    }    }

 

運行結果:

===============================color is blue====================================遍曆ColorEnum枚舉中的值====redgreenyellowblue===================================ColorEnum枚舉中的值有4個====0123-1==============================================================季節為spring==============================================================MANWOMEN==============================================================已取消待審核等待付款正在配貨等待發貨已發貨已收貨=======================================valueOf方法應用========請輸入winter-3-2-10===============================******EnumSet的用法********redgreenyellowblue******EnumMap的用法********red:is redgreen:is greenyellow:is yellowblue:is blue

 總結:

拋開具體程式設計語言來看,枚舉所具有的核心功能應該是:

◆型別安全(Type Safety) 
◆緊湊有效枚舉數值定義(Compact, Efficient Declaration of Enumerated Values) 
◆無縫的和程式其它部分的互動操作(Seamless integration with other language features) 
◆啟動並執行高效率(Runtime efficiency)

1.型別安全

枚舉的申明建立了一個新的類型。它不同於其他的已有類型,包括原始類型(整數,浮點數等等)和當前範圍(Scope)內的其它的枚舉類型。當你對函數的參數進行賦值操作的時候,整數類型和枚舉類型是不能互換的(除非是你進行顯式的類型轉換),編譯器將強制這一點。

2. 緊湊有效枚舉數值定義

定義枚舉的程式應該很簡單。

3.無縫的和程式其它部分的互動操作

語言的運算子,如賦值,相等/大於/小於判斷都應該支援枚舉。枚舉還應該支援數組下標以及witch/case語句中用來控制流程程的操作。

4. 啟動並執行高效率

枚舉的運行效率應該和原始類型的整數一樣高。在運行時不應該由於使用了枚舉而導致效能比使用整數有所下降。如果一種語言滿足這四點要求,那麼我們可以說這種語言是真正的支援枚舉。比如前面所說的Pascal,Ada,和C++。很明顯,Java不是。

Java的創始人James Gosling是個資深的C++程式員,他很清楚什麼是枚舉。但似乎他有意的刪除了Java的枚舉能力。其原因我們不得而知。可能是他想強調和鼓勵使用多態性(polymorphism),不鼓勵使用多重分支。而多重分支往往是和枚舉聯合使用的。不管他的初衷如何,我們在Java中仍然需要枚舉。

 

相關文章

聯繫我們

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

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

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.