Java 枚舉


 

2021年10月11日,最近有點忙...說好要好好學習😥 每天10點學習兩小時的我又:咕咕了🕊...

本人學習主要來源於尚硅谷個人源碼地址

Java 枚舉

枚舉 enum

什么是枚舉類:

Java 枚舉是一個特殊的類,一般表示一組常量

  • 比如: 一年的 4 個季節,一個年的 12 個月份,一個星期的 7 天,方向有東南西北等...

  • 類似這種當一個變量有幾種固定可能的取值時, 可以將它定義為枚舉類型

出現:

  • Java1.5 之前是沒有枚舉注解的.

  • 那時候一般用接口常量來替代而使用 Java 枚舉類型 enum 可以更貼近地表示這種常量.還可以配合 Switch使用...

枚舉類的實現:

  • JDK1.5 之前需要自定義枚舉類.

  • JDK 1.5 新增的 enum 關鍵字用於定義枚舉類.

  • 若枚舉只有一個對象, 則可以作為一種單例模式的實現方式.

 

1.5之前 自定義實現枚舉類:

  • 私有化類的構造器,保證不能在類的外部創建其對象

  • 在類的內部創建枚舉類的實例,聲明為:public static final 確保對象不會更改~

  • 對象如果有實例變量,應該聲明為:private final通過構造器初始化

SeasonTest1.Java

Season.Java

 package com.wsm;
 /**
  * 自定義枚舉類學習 Season季節: 一年有四個季節是固定是剛好用來做枚舉類
  */
 public class SeasonTest1 {
     public static void main(String[] args) {
         //春天
         Season chu = Season.SPRING;
         System.out.println(chu.toString());
         /**
          * ok,這就是自定義枚舉類, 類的對象是有固定個數的!且不可更改, 救像一種規則固定的對象...
          *     常用於規則狀態的定義: 商品: 缺貨 代發貨 待付款...等固定的狀態;
          * */
    }
 }
 
 class Season{
     //1.私有化類的構造器,並給對象屬性賦值: 如果有對象屬性的話順便給屬性賦值~
     private Season(String seasonName,String seasonDesc){
         this.seasonName = seasonName;
         this.seasonDesc = seasonDesc;
    }
 
     //2.聲明Season對象的屬性:private final修飾,因為枚舉對象是固定的不能更改的.
     private final String seasonName;
     private final String seasonDesc;
 
     //3.創建當前類的 固定數量的對象(一年四季): public static final的
         //因為是私有的構造函數,類中進行創建... 如果枚舉類只有一個對象,則就是一種單例模式! `餓漢式`
     public static final Season SPRING = new Season("春天","春暖花開");
     public static final Season SUMMER = new Season("夏天","夏日炎炎");
     public static final Season AUTUMN = new Season("秋天","秋高氣爽");
     public static final Season WINTER = new Season("冬天","冰天雪地");
 
     //ok,到這兒,自定義的枚舉類就創建好了
     //如果還有其它需求可以進行擴展... 創建方法:
 
     /** 獲取枚舉類對象的屬性 */
     /** 常量只有get(); 方法 */
     public String getSeasonName() {
         return seasonName;
    }
     public String getSeasonDesc() {
         return seasonDesc;
    }
 
     /** toString()方法 */
     @Override
     public String toString() {
         return "Season{" +
                 "seasonName='" + seasonName + '\'' +
                 ", seasonDesc='" + seasonDesc + '\'' +
                 '}';
    }
 }
  • JDK5 之前, 的枚舉類需要通過改方法進行自定義~

Java中被 Final修飾的變量的幾種賦值方式

  • Final 表示"最后的、最終的"含義,變量一旦賦值后,不能被重新賦值

  • 被 Final 修飾的實例變量必須顯式指定初始值

  • Final 修飾符通常和 static 修飾符一起使用來創建類常量

非靜態Final賦值有三種:定義初始化、非靜態代碼塊、構造方法

 /*定義初始化時進行賦值
 在聲明對象時直接賦值,賦值后就不可變了,這種是最容易想到的
 */
 public class FinalTest {
     private final Integer num = 10;
 }
 
 /*代碼塊中賦值
 這種是在定義之初不進行賦值操作,而是在代碼塊中進行賦值,也是可以的
 構造塊會在創建對象時被調用,每次創建時都會被調用,優先於類構造函數執行.
 */
 public class FinalTest {
     private final Integer num;
 
    {
         num = 10;
    }
 }
 
 /*
 構造器中賦值
 在創建對象時進行賦值,一旦對象創建完成,就不可變了,所以在創建完對象后set()方法是不能進行賦值的
 */
 public class FinalTest {
     private final Integer num;
     
     public FinalTest(Integer num) {
         this.num = num;
    }
 }

 

靜態使用Final:static final

  • static final賦值有兩種:定義初始化、靜態代碼塊

 /* 定義初始化 */
 public class FinalTest {
     private static final Integer num = 10 ;
 }
 
 /* 靜態代碼塊
 用static{}包裹起來的代碼片段,只會執行一次 靜態代碼塊優先於構造塊執行.
 */
 public class FinalTest {
     private static final Integer num;
     static {
         num = 10;
    }
 }

 

enum 關鍵字實現枚舉類:

  • enum 定義的枚舉類默認繼承了 Java.lang.Enum類:因此不能再 extends 繼承其他類但可以 implements

  • 枚舉類的構造器只能使用 private 權限修飾符

  • 必須在枚舉類的第一行聲明枚舉類對象

JDK 1.5 中可以在 switch 表達式中使用Enum定義的枚舉類的對象 作為表達式

case 子句可以直接使用枚舉值的名字(無需添加枚舉類作為限定)

SeasonTest2.Java

Season.Java

 package com.wsm.two;
 
 import javax.sound.midi.Soundbank;
 
 /***
  * JDK1.5 新增enum
  */
 public class SeasonTest2 {
     public static void main(String[] args) {
         /** 秋天 */
         Season AUTUMN = Season.AUTUMN;
         System.out.println(AUTUMN);         //嘗試注釋 toString()方法輸出: AUTUMN (對象名)
         //enum extends Java.lang.enum類
 
         /** enum常用方法 */
         //values()方法:
         // 返回枚舉類型的對象數組。該方法可以很方便地遍歷所有的枚舉值
         //valueOf(String str)
         // 可以把一個字符串轉為對應的枚舉類對象。要求字符串必須是枚舉類對象的“名字”。如不是,會有運行時異常:IllegalArgumentException。
         //toString()           返回當前枚舉類對象常量的名稱
         /** values() */
         System.out.println("enum常用方法values()");
         Season[] values = Season.values();              //返回該enum 的所有對象
         //遍歷結果集
         for (Season value : values) {
             System.out.println(value);
        }
 
         /** valueOf(String str) */
         System.out.println("enum常用方法valueOf(String str)");
         Season winter = Season.valueOf("WINTER");       //根據固定對象名,返回對應的enum
         System.out.println(winter);
 
         /** switch用法
          *     判斷對象屬於那一個...
          * */
         System.out.println("enum switch用法");
         switch (winter){
             case SPRING:
                 System.out.println("春");
              break;
             case SUMMER:
                 System.out.println("夏");
                 break;
             case AUTUMN:
                 System.out.println("秋");
                 break;
             case WINTER:
                 System.out.println("冬");
                 break;
             default:
                 System.out.println("沒有匹配!");
        }
         
    }
 }
 
 /** 可以於自定義枚舉進行比較查看~ */
 enum Season{
     //1.必須在枚舉類的第一行聲明枚舉類對象
     //枚舉類的所有實例必須在枚舉類中顯式列出(, 分隔 ; 結尾)
     //因為枚舉,本機不可修改由類訪問可以取消: public static final 類
 //   public static final Season SPRING = new Season("春天","春暖花開");
     SPRING("春天","春暖花開"),
     SUMMER("夏天","夏日炎炎"),
     AUTUMN("秋天","秋高氣爽"),
     WINTER("冬天","冰天雪地");
 
     //2.聲明Season對象的屬性:private final修飾
     private final String seasonName;
     private final String seasonDesc;
 
     //3.私有化類的構造器,並給對象屬性賦值
     private Season(String seasonName,String seasonDesc){
         this.seasonName = seasonName;
         this.seasonDesc = seasonDesc;
    }
 
     //擴展方法
     /** get */
     public String getSeasonName() {
         return seasonName;
    }
 
     public String getSeasonDesc() {
         return seasonDesc;
    }
 
     /** toString
      *     注釋方法直接輸出發現,即使不重新toString(); 也不是打印對象的: 地址值(棧指向堆的地址!)
      *     因為: enum類,是繼承於 Java.lang.enum的,而不是 Object類
      * */
 //   @Override
 //   public String toString() {
 //       return "Season{" +
 //               "seasonName='" + seasonName + '\'' +
 //               ", seasonDesc='" + seasonDesc + '\'' +
 //               '}';
 //   }
 }

enum 常用方法

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

enum 高級:implements實現類

  • enum 類繼承了 java.lang.enum類 Java單根性所以不能在繼承, 但Java 可以 多實現

  • eunm 類 還可以 實現接口...達到擴展的方式

實現方式:

  • 正常實現,重寫方法....但這樣所有的對象, 方法實現都一樣!

    SeasonTest3

    Season

    Info

     public class SeasonTest3 {
         public static void main(String[] args) {
             Season autumn = Season.AUTUMN;
             autumn.show();
        }
     }
     
     //使用enum關鍵字枚舉類 implements 實現接口,重寫show()方法~
     enum Season implements Info{
         SPRING("春天","春暖花開"),
         SUMMER("夏天","夏日炎炎"),
         AUTUMN("秋天","秋高氣爽"),
         WINTER("冬天","冰天雪地");
     
         //2.聲明Season對象的屬性:private final修飾
         private final String seasonName;
         private final String seasonDesc;
     
         //3.私有化類的構造器,並給對象屬性賦值
     
         private Season(String seasonName,String seasonDesc){
             this.seasonName = seasonName;
             this.seasonDesc = seasonDesc;
        }
     //重寫接口的方法!
         @Override
         public void show() {
             System.out.println("這是一個季節~");
        }
     }
     
     /** 接口 */
     interface Info{
         void show();
     }
  • 給每個enum 對象,來一個特有的固定實現!

     public class SeasonTest4 {
         public static void main(String[] args) {
             Season autumn = Season.AUTUMN;
             autumn.show();
        }
     }
     
     //使用enum關鍵字枚舉類 implements 實現接口,重寫show()方法~
     enum Season implements Info {
         SPRING("春天","春暖花開"){
             @Override
             public void show() { System.out.println("春天在哪里?"); }
        },
         SUMMER("夏天","夏日炎炎"){
             @Override
             public void show() { System.out.println("寧夏");   }
        },
         AUTUMN("秋天","秋高氣爽"){
             @Override
             public void show() { System.out.println("秋天不回來");   }
        },
         WINTER("冬天","冰天雪地"){
             @Override
             public void show() { System.out.println("大約在冬季"); }
        };
     
         //2.聲明Season對象的屬性:private final修飾
         private final String seasonName;
         private final String seasonDesc;
     
         //3.私有化類的構造器,並給對象屬性賦值
         private Season(String seasonName,String seasonDesc){
             this.seasonName = seasonName;
             this.seasonDesc = seasonDesc;
        }
     }
     
     /** 接口 */
     interface Info{
         void show();
     }

枚舉集合

在 Java 語言中和枚舉類相關的,還有兩個枚舉集合類java.util.EnumSetjava.util.EnumMap

使用 EnumSet 可以保證元素不重復,並且能獲取指定范圍內的元素

 public class EnumTest {
     public static void main(String[] args) {
         List<ErrorCodeEnum> list = new ArrayList<ErrorCodeEnum>();
         list.add(ErrorCodeEnum.SUCCESS);
         list.add(ErrorCodeEnum.SUCCESS); //重復元素
         list.add(ErrorCodeEnum.SYS_ERROR);
         list.add(ErrorCodeEnum.NAMESPACE_NOT_FOUND);
         // 去掉重復數據
         EnumSet<ErrorCodeEnum> enumSet = EnumSet.copyOf(list);
         System.out.println("去重:" + enumSet);
 
         // 獲取指定范圍的枚舉(獲取所有的失敗狀態)
         EnumSet<ErrorCodeEnum> errorCodeEnums = EnumSet.range(ErrorCodeEnum.ERROR, ErrorCodeEnum.UNKNOWN_ERROR);
         System.out.println("所有失敗狀態:" + errorCodeEnums);
    }
 }
 
 enum ErrorCodeEnum {
     SUCCESS(1000, "success"),
     ERROR(2001, "parameter error"),
     SYS_ERROR(2002, "system error"),
     NAMESPACE_NOT_FOUND(2003, "namespace not found"),
     NODE_NOT_EXIST(3002, "node not exist"),
     NODE_ALREADY_EXIST(3003, "node already exist"),
     UNKNOWN_ERROR(9999, "unknown error");
 
     private int code;
     private String msg;
 
     ErrorCodeEnum(int code, String msg) {
         this.code = code;
         this.msg = msg;
    }
 
     public int code() {   return code; }
 
     public String msg() { return msg;   }
 }
  • EnumMapHashMap 類似,不過它是一個專門為枚舉設計的 Map 集合

  • 相比 HashMap 來說它的性能更高,因為它內部放棄使用鏈表和紅黑樹的結構,采用數組作為數據存儲的結構

    • 以枚舉作為 key,查詢直接找到對應的 數組下標快速定位元素

       EnumMap<枚舉對象,Object>

       

 

為什么使用枚舉?😕

更強的類型約束

  • 在枚舉沒有誕生之前,也就是 JDK 1.5 版本之前

  • 我們通常會使用 int 常量來表示枚舉,用來區分,狀態類型: B站上傳視頻為例,視頻一般有三個狀態:草稿審核發布

    int類型本身並不具備安全性,假如某個程序員在定義int時少些了一個final關鍵字,

    那么就會存在被其他人修改的風險,反觀枚舉類,它“天然”就是一個常量類,不存在被修改的風險。

    使用 int 類型的語義不夠明確枚舉更加清晰表示一種狀態

單例模式:

  • 使用枚舉實現 單例模式更加簡單!

線程安全:

  • 枚舉類最終會被編譯為被 final 修飾的普通類

  • 它的所有屬性也都會被 staticfinal 關鍵字修飾,所以枚舉類在項目啟動時就會被 JVM 加載並初始化 且不允許更改!線程安全

方便比較:

  • 枚舉比較時使用 == 就夠了,因為枚舉類是在程序加載時就創建了(它並不是 new 出來的)每個對象全局只有一個!

  • == 比較地址,相同對象的地址也相同!

 

ok, 枚舉就介紹到這兒了,晚安,集美門😘

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM