在博客系統中,一篇文章有且可能有這幾種狀態, 數據庫中article
文章表中state
字段存儲數值,表示其狀態:java
文章實體類中用整數類型的state實例變量標識狀態:程序員
public class Article { /* 文章狀態可能值:0,1,2 */ private int state; ... }
Service
層調用DAO
層修改文章狀態爲‘已發表’:數據庫
/** * dao接口修改文章狀態方法 * @param articleId 文章ID * @param state 狀態 */ int updateState(int articleId, int state); // `Service`層修改文章狀態的調用Dao代碼: articleDao.updateState(id, 0);
以上代碼有兩個問題:編程
state
參數傳遞並無限定範圍(0,1,2);先來解決第二個問題, 在JDK1.5前經常使用的解決方式:mybatis
/** * 定義了文章的狀態 */ public interface ArticleState{ // 發佈狀態 int PUBLISHED = 0; // 草稿狀態 int DRAFT = 1; // 撤回狀態 int DELETE = 2; }
此時修改文章狀態的代碼:函數
articleDao.updateState(id, ArticleState.PUBLISHED);
然而此處沒有限制必須經過ArticleState
傳遞參數,JDK1.5後提供了枚舉來解決這類問題。工具
在java中,使用enum
關鍵字聲明枚舉類測試
/** * 文章狀態枚舉類 */ public enum ArticleStateEnum{ PUBLISHED, DRAFT, DELETE; }
而後修改DAO接口:this
/** * dao接口修改文章狀態方法 * @param articleId 文章ID * @param state 狀態 */ int updateState(int id, ArticleStateEnum state);
接着Service調用:code
// 修改文章狀態爲發表 articleDao.updateState(id, ArticleStateEnum.PUBLISHED);
以上代碼語義清晰,如今傳遞參數的類型爲ArticleStateEnum
, 解決了以前描述的兩個問題
使用JDK附帶工具javap
反編譯生枚舉類字節碼, 注javap反編譯只會獲得public成員:
看反編譯的獲得的代碼:
java.lang.Enum<>
, 意味着枚舉類不容許顯式使用extends聲明父類,包括聲明爲java.lang.Enum<>
也會報錯;public static final
修飾符實現,ArticlestateEnum
類型聲明,意味着全部枚舉常量本質是當前枚舉類的對象;values()方法
,valueOf(String)方法
;這些轉換工做是javac
編譯器幫咱們實現的,JVM並不知道枚舉的存在,javac幫咱們作了一些語法上的轉化、簡化程序員編程,這種方式稱爲語法糖。
枚舉類就是類,按照這個邏輯來測試下它和普通類的差異
添加構造函數:
紅色行提示編譯錯誤「找不到這樣的構造函數」,常量聲明處添加參數,以下代碼正確:
public enum ArticleStateEnum{ PUBLISHED(0, "已發佈"), DRAFT(1, "草稿"), DELETE(2, "撤銷"); /** 表明的數值 */ private int value; /** 信息提示 */ private String message; ArticleStateEnum(int value, String message) { this.value = value; this.message = message; } // get方法 }
能夠推測到常量聲明的地方,等價於調用構造函數,一般咱們都會爲字段添加GET方法不添加SET方法,保證枚舉常量的不變性。
枚舉類VS普通類的不一樣點:
private
;看看如下如此誇張的寫法,也能編譯成功:
觀察生成的字節碼文件:
把枚舉常量聲明的地方替換成構造方法調用new ArticleStateEnum(v1, m1)
,這不就是匿名類的聲明嗎!
如今向枚舉類內添加抽象方放,看看結果:
編譯報錯「提示有抽象方法未實現」,驗證了前面的猜測,這是匿名類的實現,不過不能夠顯式的使用使用匿名實現枚舉類的方式!
詳細參見API文檔Enum類:
public enum ArticleStateEnum{ PUBLISHED, DRAFT, DELETE; public static void main(String[] args) { ArticleStateEnum[] states = ArticleStateEnum.values(); // 1. 得到全部枚舉常量 for(ArticleStateEnum state: states) { System.out.println("序號:" + state.ordinal() + " 名字:" + state); //2. 輸出聲明序號和名稱 } System.out.println("......................................"); ArticleStateEnum draft = ArticleStateEnum.valueOf("DRAFT"); //3. 得到某個枚舉常量,依據字符串 if(ArticleStateEnum.DRAFT == draft) { System.out.println(ArticleStateEnum.valueOf("DRAFT").name()); //4. name方法輸出名字 } } }
輸出...
序號:0 名字:PUBLISHED 序號:1 名字:DRAFT 序號:0 名字:DELETE DRAFT
java中枚舉給咱們帶來強大的語義的時候,又因爲枚舉常量對象的本質,給咱們帶了來龐大性,不如C語言的枚舉的輕量:
在mybatis中保存帶有枚舉字段的實體時,須要你編寫轉化器(除非按照默認的聲明順序);
轉化爲JSON數據時;
建議無特殊狀況仍是使用枚舉常量,畢竟軟件的正確性是最重要的