Java中的Enum的使用與分析

JDK1.5引入了新的類型——枚舉。

用法一:常量

JDK1.5 之前,我們定義常量都是: publicstaticfianl.... 。現在好了,有了枚舉,可以把相關的常量分組到一個枚舉類型裏,而且枚舉提供了比常量更多的方法。

 

Java代碼 
  1. public enum Color {  
  2.   RED, GREEN, BLANK, YELLOW  
  3. }  

 

用法二:switch

JDK1.6之前的switch語句只支持int,char,enum類型,使用枚舉,能讓我們的代碼可讀性更強。

 

Java代碼 
  1. enum Signal {  
  2.     GREEN, YELLOW, RED  
  3. }  
  4. public class TrafficLight {  
  5.     Signal color = Signal.RED;  
  6.     public void change() {  
  7.         switch (color) {  
  8.         case RED:  
  9.             color = Signal.GREEN;  
  10.             break;  
  11.         case YELLOW:  
  12.             color = Signal.RED;  
  13.             break;  
  14.         case GREEN:  
  15.             color = Signal.YELLOW;  
  16.             break;  
  17.         }  
  18.     }  
  19. }  

 

用法三:向枚舉中添加新方法

如果打算自定義自己的方法,那麼必須在enum實例序列的最後添加一個分號。而且 Java 要求必須先定義 enum 實例。

 

Java代碼 
  1. public enum Color {  
  2.     RED("紅色"1), GREEN("綠色"2), BLANK("白色"3), YELLO("黃色"4);  
  3.     // 成員變量  
  4.     private String name;  
  5.     private int index;  
  6.     // 構造方法  
  7.     private Color(String name, int index) {  
  8.         this.name = name;  
  9.         this.index = index;  
  10.     }  
  11.     // 普通方法  
  12.     public static String getName(int index) {  
  13.         for (Color c : Color.values()) {  
  14.             if (c.getIndex() == index) {  
  15.                 return c.name;  
  16.             }  
  17.         }  
  18.         return null;  
  19.     }  
  20.     // get set 方法  
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.     public void setName(String name) {  
  25.         this.name = name;  
  26.     }  
  27.     public int getIndex() {  
  28.         return index;  
  29.     }  
  30.     public void setIndex(int index) {  
  31.         this.index = index;  
  32.     }  
  33. }  

 

用法四:覆蓋枚舉的方法

下面給出一個toString()方法覆蓋的例子。

 

Java代碼 
  1. public enum Color {  
  2.     RED("紅色"1), GREEN("綠色"2), BLANK("白色"3), YELLO("黃色"4);  
  3.     // 成員變量  
  4.     private String name;  
  5.     private int index;  
  6.     // 構造方法  
  7.     private Color(String name, int index) {  
  8.         this.name = name;  
  9.         this.index = index;  
  10.     }  
  11.     //覆蓋方法  
  12.     @Override  
  13.     public String toString() {  
  14.         return this.index+"_"+this.name;  
  15.     }  
  16. }  

 

用法五:實現接口

所有的枚舉都繼承自java.lang.Enum類。由於Java 不支持多繼承,所以枚舉對象不能再繼承其他類。

 

Java代碼 
  1. public interface Behaviour {  
  2.     void print();  
  3.     String getInfo();  
  4. }  
  5. public enum Color implements Behaviour{  
  6.     RED("紅色"1), GREEN("綠色"2), BLANK("白色"3), YELLO("黃色"4);  
  7.     // 成員變量  
  8.     private String name;  
  9.     private int index;  
  10.     // 構造方法  
  11.     private Color(String name, int index) {  
  12.         this.name = name;  
  13.         this.index = index;  
  14.     }  
  15. //接口方法  
  16.     @Override  
  17.     public String getInfo() {  
  18.         return this.name;  
  19.     }  
  20.     //接口方法  
  21.     @Override  
  22.     public void print() {  
  23.         System.out.println(this.index+":"+this.name);  
  24.     }  
  25. }  

 

用法六:使用接口組織枚舉

 

Java代碼 
  1. public interface Food {  
  2.     enum Coffee implements Food{  
  3.         BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
  4.     }  
  5.     enum Dessert implements Food{  
  6.         FRUIT, CAKE, GELATO  
  7.     }  
  8. }  


  9. 用法七:關於枚舉集合的使用

    java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重複;EnumMap中的 key是enum類型,而value則可以是任意類型。關於這個兩個集合的使用就不在這裏贅述,可以參考JDK文檔

    枚舉和常量定義的區別

    一、 通常定義常量方法

    我們通常利用public final static方法定義的代碼如下,分別用1表示紅燈,3表示綠燈,2表示黃燈。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    publicclass Light {
        /* 紅燈 */
        public final static int RED = 1;
     
        /* 綠燈 */
        public final static int GREEN = 3;
     
        /* 黃燈 */
        publicfinal static int YELLOW = 2;
      }

    二、 枚舉類型定義常量方法

    枚舉類型的簡單定義方法如下,我們似乎沒辦法定義每個枚舉類型的值。比如我們定義紅燈、綠燈和黃燈的代碼可能如下:

    ?
    1
    2
    3
    publicenum Light {
        RED, GREEN, YELLOW;
      }

    我們只能夠表示出紅燈、綠燈和黃燈,但是具體的值我們沒辦法表示出來。別急,既然枚舉類型提供了構造函數,我們可以通過構造函數和覆寫toString方法來實現。首先給Light枚舉類型增加構造方法,然後每個枚舉類型的值通過構造函數傳入對應的參數,同時覆寫toString方法,在該方法中返回從構造函數中傳入的參數,改造後的代碼如下:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    publicenum Light {
     
      // 利用構造函數傳參
      RED(1), GREEN(3), YELLOW(2);
     
      // 定義私有變量
      privateint nCode;
     
      // 構造函數,枚舉類型只能爲私有
      privateLight(int_nCode) {
     
        this.nCode = _nCode;
     
      }
     
      @Override
      publicString toString() {
     
        returnString.valueOf(this.nCode);
     
      }
     
    }

    三、 完整示例代碼

    枚舉類型的完整演示代碼如下:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    publicclass LightTest {
     
      // 1.定義枚舉類型
     
      publicenum Light {
     
        // 利用構造函數傳參
     
        RED(1), GREEN(3), YELLOW(2);
     
        // 定義私有變量
     
        privateint nCode;
     
        // 構造函數,枚舉類型只能爲私有
     
        privateLight(int_nCode) {
     
          this.nCode = _nCode;
     
        }
     
        @Override
        publicString toString() {
     
          returnString.valueOf(this.nCode);
     
        }
     
      }
     
      /**
       *
       * @param args
       */
     
      publicstatic void main(String[] args) {
     
        // 1.遍歷枚舉類型
     
        System.out.println("演示枚舉類型的遍歷 ......");
     
        testTraversalEnum();
     
        // 2.演示EnumMap對象的使用
     
        System.out.println("演示EnmuMap對象的使用和遍歷.....");
     
        testEnumMap();
     
        // 3.演示EnmuSet的使用
     
        System.out.println("演示EnmuSet對象的使用和遍歷.....");
     
        testEnumSet();
     
      }
     
      /**
       *
       * 演示枚舉類型的遍歷
       */
     
      privatestatic void testTraversalEnum() {
     
        Light[] allLight = Light.values();
     
        for(Light aLight : allLight) {
     
          System.out.println("當前燈name:"+ aLight.name());
     
          System.out.println("當前燈ordinal:"+ aLight.ordinal());
     
          System.out.println("當前燈:"+ aLight);
     
        }
     
      }
     
      /**
       *
       * 演示EnumMap的使用,EnumMap跟HashMap的使用差不多,只不過key要是枚舉類型
       */
     
      privatestatic void testEnumMap() {
     
        // 1.演示定義EnumMap對象,EnumMap對象的構造函數需要參數傳入,默認是key的類的類型
     
        EnumMap<Light, String> currEnumMap = newEnumMap<Light, String>(
     
        Light.class);
     
        currEnumMap.put(Light.RED,"紅燈");
     
        currEnumMap.put(Light.GREEN,"綠燈");
     
        currEnumMap.put(Light.YELLOW,"黃燈");
     
        // 2.遍歷對象
     
        for(Light aLight : Light.values()) {
     
          System.out.println("[key="+ aLight.name() + ",value="
     
          + currEnumMap.get(aLight) + "]");
     
        }
     
      }
     
      /**
       *
       * 演示EnumSet如何使用,EnumSet是一個抽象類,獲取一個類型的枚舉類型內容<BR/>
       *
       * 可以使用allOf方法
       */
     
      privatestatic void testEnumSet() {
     
        EnumSet<Light> currEnumSet = EnumSet.allOf(Light.class);
     
        for(Light aLightSetElement : currEnumSet) {
     
          System.out.println("當前EnumSet中數據爲:"+ aLightSetElement);
     
        }
     
      }
     
    }

    執行結果如下:

    演示枚舉類型的遍歷 ......

    當前燈name:RED

    當前燈ordinal:0

    當前燈:1

    當前燈name:GREEN

    當前燈ordinal:1

    當前燈:3

    當前燈name:YELLOW

    當前燈ordinal:2

    當前燈:2

    演示EnmuMap對象的使用和遍歷.....

    [key=RED,value=紅燈]

    [key=GREEN,value=綠燈]

    [key=YELLOW,value=黃燈]

    演示EnmuSet對象的使用和遍歷.....

    當前EnumSet中數據爲:1

    當前EnumSet中數據爲:3

    當前EnumSet中數據爲:2

    四、 通常定義常量方法和枚舉定義常量方法區別

    以下內容可能有些無聊,但絕對值得一窺

    1. 代碼:

    ?
    1
    2
    3
    4
    5
    6
    7
    publicclass State {
     
    publicstatic final int ON = 1;
     
    publicstatic final Int OFF= 0;
     
    }

    有什麼不好了,大家都這樣用了很長時間了,沒什麼問題啊。

    首先,它不是類型安全的。你必須確保是int

    其次,你還要確保它的範圍是0和1

    最後,很多時候你打印出來的時候,你只看到 1 和0 ,

    但其沒有看到代碼的人並不知道你的企圖,拋棄你所有舊的public static final常量

    2. 可以創建一個enum類,把它看做一個普通的類。除了它不能繼承其他類了。(java是單繼承,它已經繼承了Enum),

    可以添加其他方法,覆蓋它本身的方法

    3. switch()參數可以使用enum了

    4. values()方法是編譯器插入到enum定義中的static方法,所以,當你將enum實例向上轉型爲父類Enum是,values()就不可訪問了。解決辦法:在Class中有一個getEnumConstants()方法,所以即便Enum接口中沒有values()方法,我們仍然可以通過Class對象取得所有的enum實例

    5. 無法從enum繼承子類,如果需要擴展enum中的元素,在一個接口的內部,創建實現該接口的枚舉,以此將元素進行分組。達到將枚舉元素進行分組。

    6. 使用EnumSet代替標誌。enum要求其成員都是唯一的,但是enum中不能刪除添加元素。

    7. EnumMap的key是enum,value是任何其他Object對象。

    8. enum允許程序員爲eunm實例編寫方法。所以可以爲每個enum實例賦予各自不同的行爲。

    9. 使用enum的職責鏈(Chain of Responsibility) .這個關係到設計模式的職責鏈模式。以多種不同的方法來解決一個問題。然後將他們鏈接在一起。當一個請求到來時,遍歷這個鏈,直到鏈中的某個解決方案能夠處理該請求。

    10. 使用enum的狀態機。

    11. 使用enum多路分發。

    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) 
              返回帶指定名稱的指定枚舉類型的枚舉常量。


  10. eg:public class EnumTest {
       public static void main(String[] args) {
          forEnum();  
    //        useEnumInJava();  
       }
       
       /** 
         * 循環枚舉,輸出ordinal屬性;若枚舉有內部屬性,則也輸出。(說的就是我定義的TYPE類型的枚舉的typeName屬性) 
         */  
       private static void forEnum(){
          for(SimpleEnum simpleEnum : SimpleEnum.values()){
             System.out.println(simpleEnum +"**"+simpleEnum.name() + "  ordinal  " + simpleEnum.ordinal());
          }
          System.out.println("------------------");  
            for (TYPE type : TYPE.values()) {  
               System.out.println("type = " + type + "    type.name = " + type.name() + "   code = " + type.getCode() + "   msg = "   + type.getMsg()+"   ordinal = " + type.ordinal());
    //            System.out.println("type = " + type + "    type.name = " + type.name() + "   typeName = " + type.getTypeName() + "   ordinal = " + type.ordinal());  
            }  
       }
       
       /** 
         * 在Java代碼使用枚舉 
         */  
    // private static void useEnumInJava(){
    //    String typeName = "f5";
    //    TYPE type = TYPE.fromTypeName(typeName);
    //    if (TYPE.BALANCE.equals(type)) {  
    //            System.out.println("根據字符串獲得的枚舉類型實例跟枚舉常量一致");  
    //        } else {  
    //            System.out.println("大師兄代碼錯誤");  
    //        }  
    // }
       /**
        * 季節枚舉(不帶參數的枚舉常量)這個是最簡單的枚舉使用實例 
         * Ordinal 屬性,對應的就是排列順序,從0開始。 
        */
       private enum SimpleEnum{
          SPRING,SUMMER,AUTUMN,WINTER
       }
       
       /** 
         * 常用類型(帶參數的枚舉常量,這個只是在書上不常見,實際使用還是很多的,看懂這個,使用就不是問題啦。) 
         */  
       private enum TYPE{
          FIREWALL(2000,"firewall"),
            SECRET(3000,"secretMac"),
            success(1000, "操作成功");
    //        BALANCE("f5");
          
    //    private String typeName;
          
    //    TYPE(String typeName){
    //       this.typeName = typeName;
    //    }
          private int code;
           private String msg;
    
           TYPE(int code, String msg) {
               this.code = code;
               this.msg = msg;
           }
           public int getCode() {
               return code;
           }
           public String getMsg() {
               return msg;
           }
           /** 
             * 根據類型的名稱,返回類型的枚舉實例。 
             * 
             * @param typeName 類型名稱 
             */ 
    //    public static TYPE fromTypeName(String typeName){
    //       for(TYPE type : TYPE.values()){
    //          if(type.getTypeName().equals(typeName)){
    //             return type;
    //          }
    //       }
    //       return null;
    //    }
          
    //    public String getTypeName(){
    //       return this.typeName;
    //    }
       }
       
    }
    


發佈了42 篇原創文章 · 獲贊 29 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章