枚举类型enum用法_Java枚举深度解读,看这篇就够了
作者 | 濤GuoGuo的跟屁蟲丶博Ke
來源 | urlify.cn/aaamQf
66套java從入門到精通實戰課程分享
Java枚舉
1、枚舉類概念的理解與定義
- 一個類的對象是有限個,確定的,我們稱此為枚舉類。
- 當需要定義和維護一組常量時,強烈建議使用枚舉類。
- 如果一個枚舉類中只有一個對象,則可以作為單例模式的實現方式。
2、枚舉類的定義
關于枚舉類的定義,這塊主要想和大家分享兩種方式
3、實踐
(一)、準備工作
我們新建一個 Java Project ,并創建一個包,以及一個測試類
(二)、自定義枚舉的三種方式(jdk 5.0 之前)
1. 定義一個抽象類,在抽象類中定義常量進行維護,我們接下來以 Java 類庫中的 Calendar 類示例來進行說明
新建一個類 EnumDemo01.java 代碼如下:
package?org.taoguoguo;import?java.util.Calendar;/**?*?@author?taoGG?*?@description?jdk?5.0?之前?抽象類枚舉方案Demo?*?@create?2020-09-13?14:20?*/public?class?EnumDemo01?{????public?static?void?main(String[]?args)?{????????Calendar?calendar?=?Calendar.getInstance();????????System.out.println(calendar.get(1));????}}Console 結果輸出:
2020Process?finished?with?exit?code?0如果熟悉 Calendar API 的小伙伴 應該馬上能反應過來,這個是獲取當前的年份,類似的值還有
3?-?一年中的第幾個星期4?-?一年中的第幾個月5?-?當前的日期?......但是這么多值,我們怎么能記得住呢?萬一我輸入錯誤,隨便取了一個范圍怎么辦?
沒錯,這是 jdk 5.0之前的痛點,為了解決實例數量固定,便于維護這些問題,在jdk 5.0之后更新Enum枚舉類解決了這個問題。那在jdk 5.0之前官方是怎么做的呢?難道需要我們一個個去記住 Calendar 的數字?
實際上官方本身,采用的就是我們現在說的第一種方式,在抽象類中定義常量進行維護
現在我們將代碼做些修改:
package?org.taoguoguo;import?java.util.Calendar;/**?*?@author?taoGG?*?@description?jdk?5.0?之前?抽象類枚舉方案Demo?*?@create?2020-09-13?14:20?*/public?class?EnumDemo01?{????public?static?void?main(String[]?args)?{????????Calendar?calendar?=?Calendar.getInstance();????????System.out.println(calendar.get(Calendar.YEAR));????}}我們運行進行輸出:
2020Process?finished?with?exit?code?0結果與之前一致,這時我們就清楚,在開發過程中作為開發者我們肯定愿意使用 Calendar.YEAR 這種寫法,一來方便記憶,二來可讀性高。那么官方的做法時怎樣的呢?我們點進去源碼看一下
2. 定義一個接口,在接口中定義常量維護枚舉值
我們新建一個interface CustomerInf.java
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?接口常量維護枚舉值?*?@create?2020-09-13?15:47?*/public?interface?CustomerInf?{???int?RED?=?1;???int?GREEN?=?2;???int?BLUE?=?3;}在 EnumTest 進行測試
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?Java枚舉測試類?*?@create?2020-09-13?14:54?*?*/public?class?EnumTest?{????public?static?void?main(String[]?args)?{????????System.out.println(CustomerInf.RED);????}}測試結果:
1Process?finished?with?exit?code?0這種做法我們達到了和在抽象類中維護常量相同的目的。上面這兩種做法都非常的簡單易用,但也有弊端。比如我們只知道一個狀態值,當我們要獲取狀態的屬性或者相關的內容時,我們該怎么做呢?
下面我們使用第三種方式,自定義枚舉類,這種基本上達到和 Enum 關鍵字相同的作用,但有一點不足就是會較為復雜
3.自定義枚舉類,通過為類私有化構造器和固定實例對象進行枚舉維護
新建一個class SeasonEnum.java,代碼如下:
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?15:58?*/public?class?SeasonEnum?{????//1.聲明枚舉對象的屬性????private?final?String?seasonName;????private?final?int?code;????//2.私有化類的構造器????private?SeasonEnum(String?seasonName,int?code){????????this.seasonName?=?seasonName;????????this.code?=?code;????}????//3.提供當前枚舉類的多個對象?public?static?final????public?static?final?SeasonEnum?SPRING?=?new?SeasonEnum("春天",100);????public?static?final?SeasonEnum?SUMMER?=?new?SeasonEnum("夏天",200);????public?static?final?SeasonEnum?AUTUMN?=?new?SeasonEnum("秋天",300);????public?static?final?SeasonEnum?WINTER?=?new?SeasonEnum("冬天",400);????//4.為類提供獲取屬性的方法????public?String?getSeasonName()?{????????return?seasonName;????}????public?int?getCode()?{????????return?code;????}????//5.重寫toString方法????@Override????public?String?toString()?{????????return?"SeasonEnum{"?+????????????????"seasonName='"?+?seasonName?+?'''?+????????????????",?code="?+?code?+????????????????'}';????}}新建一個class SeasonEnumTest 進行測試,當我們通過自定義枚舉類引用實例對象時,如下圖可以看到,我們已經可以獲取到我們的枚舉對象了。
獲取到枚舉對象,我們當然也可以獲取到對應的屬性及方法,這種可用性就提高了很多,我們在開發程序進行判斷,可以根據各種枚舉值的指定屬性來進行,提高了代碼的可維護性。
SeasonEnumTest 測試代碼
根據我們上面的自定義枚舉類方式,我們基本已經實現了枚舉的功能了,但是就像上面說到的,如果開發中枚舉類型較多,開發多個這樣的自定義枚舉類會非常的耗時,所以 jdk 5.0 之后,推出了 Enum 關鍵字定義枚舉類
(三)Enum 關鍵字定義枚舉類(jdk 5.0之后)
enum 全稱為 enumeration,是jdk 5.0 中引入的新特性,在Java 中被 enum 關鍵字修飾的類型就是枚舉類型
我們通過代碼來示例來講解和理解 enum 的用法,還是用我們剛剛自定以枚舉類的例子,看看使用enum如何來寫
新建一個Java class ,Kind 類型選擇 enum 如圖:
枚舉類創建注意:
- 枚舉實例必須在 enum關鍵字聲明的類中顯式的指定(首行開始的以第一個分號結束)
- 枚舉不允許使用new,clone,反射,序列化手動創建枚舉實例
使用 SeasonTest 測試類進行測試:
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?16:27?*/public?class?SeasonTest?{????public?static?void?main(String[]?args)?{????????Season?spring?=?Season.SPRING;????????System.out.println(spring);????}}輸出結果:
SPRINGProcess?finished?with?exit?code?0注意,在enmu 枚舉類中如果沒有重寫 toString方法,會默認使用Enum類本身提供的 toString 方法,返回枚舉類名稱,因為定義的枚舉類默認隱式繼承于java.lang.Enum
1.枚舉類主要方法介紹
- values() :該方法可以返回當前枚舉類型的對象數組,可以很方便的遍歷所有枚舉值。一般我們可以根據枚舉類的相關屬性通過此方法遍歷獲取對應的枚舉對象及枚舉值
- valueOf(String str) : 根據枚舉類名稱獲取枚舉類對象
- toString(): 默認使用 java.lang.Enum的 toString方法,返回當前對象常量的名稱,枚舉類推薦重寫返回自定義友好描述
- name(): 返回當前枚舉對象名稱,和toString作用上類似,當時toString支持重寫,name方法是不能重寫的,在本質上 toString 也是調用的 name方法,枚舉定義 name 方法就是為了返回枚舉對象名稱,而 toString 應該根據需要進行重寫
- ordinal(): 返回當前枚舉對象的序號, 實現了 Comparable 接口,表明它是支持排序的 可以通過 Collections.sort 進行自動排序比較此枚舉與指定對象的順序
- compareTo(): 基于ordinal進行序號大小比較
方式演示代碼,小伙伴們可以自行運行輸出一下,看看各個方法的作用,熟悉一下相關的方法api
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?16:27?*/public?class?SeasonTest?{????public?static?void?main(String[]?args)?{????????System.out.println("========values()方法=======");????????for?(Season?season?:?Season.values())?{????????????System.out.println(season);????????}????????System.out.println("===========================");?????????System.out.println("========valueOf方法========");????????Season?spring?=?Season.valueOf("SPRING");????????System.out.println(spring);????????System.out.println("===========================");????????System.out.println("========toString方法========");????????System.out.println(spring.toString());????????System.out.println("===========================");????????System.out.println("========name方法========");????????System.out.println(spring.name());????????System.out.println("===========================");????????System.out.println("========ordinal方法========");????????System.out.println(spring.ordinal());????????System.out.println("===========================");????????System.out.println("========compareTo方法========");????????System.out.println(spring.compareTo(Season.WINTER));????????System.out.println("===========================");????}}2.枚舉類對接口的實現方式
準備工作
新建一個EnumInf 接口,定義一個抽象方法
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:25?*/public?interface?EnumInf?{????void?show();}1.實現接口,在enum中統一實現抽象方法
新建一個EnumInf 接口,定義抽象方法 show()
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:25?*/public?interface?EnumInf?{????void?show();}新建一個OrderStatus 枚舉類 實現 EnumInf 接口
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:27?*/public?enum?OrderStatus?implements?EnumInf{????SUCCESS(200,"交易成功"),????Fail(500,"交易失敗");????private?final?int?code;????private?final?String?desc;????OrderStatus(int?code,?String?desc){????????this.code?=?code;????????this.desc?=?desc;????}????public?int?getCode()?{????????return?code;????}????public?String?getDesc()?{????????return?desc;????}????/**?????*?第一種方式,枚舉統一重寫接口抽象方法?????*/????@Override????public?void?show()?{????????System.out.println("訂單枚舉對象");????}}進行測試
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:32?*/public?class?OrderStatusTest?{????public?static?void?main(String[]?args)?{????????OrderStatus?success?=?OrderStatus.SUCCESS;????????success.show();????}}輸出結果
訂單枚舉對象Process?finished?with?exit?code?0跟我們常用類實現沒有什么區別,枚舉也是可以統一實現的,那如果想針對不同的枚舉對象進行不同狀態的實現怎么辦呢?比如我們的OA系統、或者電商系統中,根據不同狀態 我們需要回寫對應的數據,下面我們就來看看如何實現。
2.枚舉對象分別實現接口中的抽象方法
案例跟接口統一實現一致,我們這邊修改一下OrderStatus 枚舉類,代碼如下
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:27?*/public?enum?OrderStatus?implements?EnumInf{????SUCCESS(200,"交易成功")?{????????@Override????????public?void?show()?{????????????System.out.println("回寫交易成功狀態");????????}????},????Fail(500,"交易失敗")?{????????@Override????????public?void?show()?{????????????System.out.println("回寫交易失敗狀態");????????}????};????private?final?int?code;????private?final?String?desc;????OrderStatus(int?code,?String?desc){????????this.code?=?code;????????this.desc?=?desc;????}????public?int?getCode()?{????????return?code;????}????public?String?getDesc()?{????????return?desc;????}}我們再修改下測試類代碼:
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?17:32?*/public?class?OrderStatusTest?{????public?static?void?main(String[]?args)?{????????OrderStatus?success?=?OrderStatus.SUCCESS;????????success.show();????????OrderStatus?fail?=?OrderStatus.Fail;????????fail.show();????}}輸出結果
回寫交易成功狀態回寫交易失敗狀態Process?finished?with?exit?code?0通過這種方式就可以輕而易舉地定義每個枚舉實例不同的行為方式,也達到了我們預期的效果,其實在開發過程中根據枚舉的設計和設計模式的鋪墊可以極大的簡化我們的業務代碼。
3.Enum枚舉類的工具類及應用場景
1.EnumSet 和 EnumMap
Java 中提供了兩個方便操作enum的工具類——EnumSet 和 EnumMap。
EnumSet 是枚舉類型的高性能 Set 實現。它要求放入它的枚舉常量必須屬于同一枚舉類型。
//?EnumSet的使用System.out.println("EnumSet展示");EnumSet?errSet?=?EnumSet.allOf(OrderStatus.class);for?(OrderStatus?e?:?errSet)?{????System.out.println(e.name()?+?"?:?"?+?e.ordinal());}EnumMap 是專門為枚舉類型量身定做的 Map 實現。雖然使用其它的 Map 實現(如HashMap)也能完成枚舉類型實例到值得映射,但是使用 EnumMap 會更加高效:它只能接收同一枚舉類型的實例作為鍵值,并且由于枚舉類型實例的數量相對固定并且有限,所以 EnumMap 使用數組來存放與枚舉類型對應的值。(計算機處理連續的資源使用局部內存效率更高)這使得 EnumMap 的效率非常高。
//?EnumMap的使用System.out.println("EnumMap展示");EnumMap?errMap?=?new?EnumMap(StateMachine.Signal.class);errMap.put(StateMachine.Signal.RED,?"紅燈");errMap.put(StateMachine.Signal.YELLOW,?"黃燈");errMap.put(StateMachine.Signal.GREEN,?"綠燈");for?(Iterator>?iter?=errMap.entrySet().iterator();?iter.hasNext();)?{????Map.Entry?entry?=?iter.next();????System.out.println(entry.getKey().name()?+?"?:?"?+?entry.getValue());}2.枚舉類與 Switch 的配合使用
關于枚舉與switch是個比較簡單的話題,使用switch進行條件判斷時,條件參數一般只能是整型,字符型。而枚舉型確實也被switch所支持,在java 1.7后switch也對字符串進行了支持。
實踐
新建一個 BizEnum 的java class,代碼如下
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?企業類型枚舉?*?@create?2020-09-13?21:24?*/public?enum?BizEnum?{????COUNTRIES(101,"國有企業"),????PRIVETE(102,"私營企業"),????SOHO(103,"個體單位");????private?final?int?code;????private?final?String?desc;????BizEnum(int?code,?String?desc){????????this.code?=?code;????????this.desc?=?desc;????}????public?int?getCode()?{????????return?code;????}????public?String?getDesc()?{????????return?desc;????}????//根據編碼獲取當前枚舉對象的方法????public?static?BizEnum?getBizTypeByCode(int?code){????????for?(BizEnum?bizEnum?:?BizEnum.values())?{????????????if(code?==?bizEnum.getCode()){????????????????return?bizEnum;????????????}????????}????????return?null;????}}結合Switch進行測試
package?org.taoguoguo;/**?*?@author?taoGG?*?@description?*?@create?2020-09-13?21:31?*/public?class?BizTest?{????public?static?void?main(String[]?args)?{????????BizEnum?bizType?=?BizEnum.getBizTypeByCode(101);????????switch?(bizType){????????????case?COUNTRIES:????????????????System.out.println("國有企業");????????????????break;????????????case?PRIVETE:????????????????System.out.println("私營企業");????????????????break;????????????case?SOHO:????????????????System.out.println("個體單位");????????????????break;????????????default:????????????????System.out.println("創業中");????????}????}}輸出結果:
國有企業Process?finished?with?exit?code?0總結
總結
以上是生活随笔為你收集整理的枚举类型enum用法_Java枚举深度解读,看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单例模式双重校验锁_被面试官虐过之后,他
- 下一篇: python编程免费教程电子书_pyth