Java列舉
列舉類概念的理解與定義
- 一個類的物件是有限個,確定的,我們稱此為列舉類,
- 當需要定義和維護一組常量時,強烈建議使用列舉類,
- 如果一個列舉類中只有一個物件,則可以作為單例模式的實作方式,
通俗的說:一個類被設計為包含固定實體數量的特殊類,我們給他的定義是列舉類,
注意:
1.列舉類不能被 new 出來,列舉類因為默認的類修飾符為 final 所以也不能被派生(繼承),同理列舉類也不能為當作實作,
2.列舉類自身可以實作介面,既可以進行統一實作重寫介面抽象方法,也可以按照列舉型別單個實作重寫,
列舉類的定義
關于列舉類的定義,這塊主要想和大家分享兩種方式
- jdk 5.0之前,自定義列舉類方式
- jdk 5.0之后,Enum關鍵字方式定義
實踐
一、準備作業
我們新建一個 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 結果輸出:
2020
Process 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));
}
}
我們運行進行輸出:
2020
Process finished with exit code 0
結果與之前一致,這時我們就清楚,在開發程序中作為開發者我們肯定愿意使用 Calendar.YEAR 這種寫法,一來方便記憶,二來可讀性高,那么官方的做法時怎樣的呢?我們點進去原始碼看一下
-
首先 Calendar 本身是一個抽象類,實作了序列化、克隆、以及比較排序介面,這邊和我們列舉沒有太大關系,我們繼續往下看

-
在抽象類中,定義了很多個靜態常量進行維護,而當我們需要使用時,直接呼叫,這樣就比我們寫一個個的具體值要方便和易用了,

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);
}
}
測驗結果:
1
Process 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 測驗代碼
package org.taoguoguo;
/**
* @author taoGG
* @description
* @create 2020-09-13 16:04
*/
public class SeasonEnumTest {
public static void main(String[] args) {
SeasonEnum spring = SeasonEnum.SPRING;
System.out.println("自定義列舉類物件:" + spring);
System.out.println("自定義列舉類屬性:" + spring.getSeasonName());
System.out.println("自定義列舉類屬性:" + spring.getCode());
}
}
根據我們上面的自定義列舉類方式,我們基本已經實作了列舉的功能了,但是就像上面說到的,如果開發中列舉型別較多,開發多個這樣的自定義列舉類會非常的耗時,所以 jdk 5.0 之后,推出了 Enum 關鍵字定義列舉類
三、Enum 關鍵字定義列舉類(jdk 5.0之后)
enum 全稱為 enumeration,是jdk 5.0 中引入的新特性,在Java 中被 enum 關鍵字修飾的型別就是列舉型別
我們通過代碼來示例來講解和理解 enum 的用法,還是用我們剛剛自定以列舉類的例子,看看使用enum如何來寫
新建一個Java class ,Kind 型別選擇 enum 如圖:

列舉類創建注意:
- 列舉實體必須在
enum關鍵字宣告的類中顯式的指定(首行開始的以第一個分號結束) - 列舉不允許使用new,clone,反射,序列化手動創建列舉實體
package org.taoguoguo;
/**
* @author taoGG
* @description
* @create 2020-09-13 16:23
*/
public enum Season {
SPRING("春天",100),
SUMMER("夏天",200),
AUTUMN("秋天",300),
WINTER("冬天",400);
private final String seasonName;
private final int code;
Season(String seasonName, int code){
this.seasonName = seasonName;
this.code = code;
}
public String getSeasonName() {
return seasonName;
}
public int getCode() {
return code;
}
}
使用 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);
}
}
輸出結果:
SPRING
Process 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<OrderStatus> 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<StateMachine.Signal, String> errMap = new EnumMap(StateMachine.Signal.class);
errMap.put(StateMachine.Signal.RED, "紅燈");
errMap.put(StateMachine.Signal.YELLOW, "黃燈");
errMap.put(StateMachine.Signal.GREEN, "綠燈");
for (Iterator<Map.Entry<StateMachine.Signal, String>> iter =errMap.entrySet().iterator(); iter.hasNext();) {
Map.Entry<StateMachine.Signal, String> 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
總結
- jdk 5.0之前我們可以自定義列舉類,jdk 5.0之后使用
enum關鍵字定義列舉類,列舉類默認繼承自java.lang.Enum,使用列舉類將常量組織起來,便于統一管理,例如錯誤碼、狀態機等場景中,較為合適使用列舉類, - 列舉類常用方法介紹及列舉類實作抽象類、介面等抽象方法的兩種方式,
- 列舉常用的工具類及與
switch使用的場景,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/29073.html
標籤:Java
上一篇:簡單明了的設計模式-立意篇
下一篇:mybatis 學習筆記
