枚舉類型是Java 5中新增特性的一部分,它是一種特殊的數據類型,之因此特殊是由於它既是一種類(class)類型卻又比類類型多了些特殊的約束,可是這些約束的存在也造就了枚舉類型的簡潔性、安全性以及便捷性。
△有的地方尚未學的透徹,以後會繼續學習修改更新本文章
以下定義週一到週日的常量javascript
//Day.class //枚舉類型,使用關鍵字enum enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
至關簡潔,在定義枚舉類型時咱們使用的關鍵字是enum,與class關鍵字相似,只不過前者是定義枚舉類型,後者是定義類類型。css
咱們大概瞭解了枚舉類型的定義與簡單使用後,如今有必要來了解一下枚舉類型的基本實現原理。實際上在使用關鍵字enum
建立枚舉類型並編譯後,編譯器會爲咱們生成一個相關的類,這個類繼承了Java API
中的java.lang.Enum
類,也就是說經過關鍵字enum
建立枚舉類型在編譯後事實上也是一個類類型並且該類繼承自java.lang.Enum
類。html
查看反編譯Day.class文件:java
//反編譯Day.class final class Day extends Enum { //編譯器爲咱們添加的靜態的values()方法 public static Day[] values() { return (Day[])$VALUES.clone(); } //編譯器爲咱們添加的靜態的valueOf()方法,注意間接調用了Enum也類的valueOf方法 public static Day valueOf(String s) { return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s); } //私有構造函數 private Day(String s, int i) { super(s, i); } //前面定義的7種枚舉實例 public static final Day MONDAY; public static final Day TUESDAY; public static final Day WEDNESDAY; public static final Day THURSDAY; public static final Day FRIDAY; public static final Day SATURDAY; public static final Day SUNDAY; private static final Day $VALUES[]; static { //實例化枚舉實例 MONDAY = new Day("MONDAY", 0); TUESDAY = new Day("TUESDAY", 1); WEDNESDAY = new Day("WEDNESDAY", 2); THURSDAY = new Day("THURSDAY", 3); FRIDAY = new Day("FRIDAY", 4); SATURDAY = new Day("SATURDAY", 5); SUNDAY = new Day("SUNDAY", 6); $VALUES = (new Day[] { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }); } }
java.lang.Enum
類,該類是一個抽象類(稍後咱們會分析該類中的主要方法)。values()和 valueOf()
。MONDAY
枚舉類型對應public static final Day MONDAY;
,同時編譯器會爲該類建立兩個方法,分別是values()和valueOf()
。到此相信咱們對枚舉的實現原理也比較清晰。下面咱們深刻了解一下java.lang.Enum類以及values()和valueOf()的用途。
系統裏實現常量的三種方式接口常量、類常量、枚舉常量程序員
如java的swing裏有一個SwingConstant:數據庫
public interface SwingConstants { /** * The central position in an area. Used for * both compass-direction constants (NORTH, etc.) * and box-orientation constants (TOP, etc.). */ public static final int CENTER = 0; // // Box-orientation constant used to specify locations in a box. // /** * Box-orientation constant used to specify the top of a box. */ public static final int TOP = 1; /** * Box-orientation constant used to specify the left side of a box. */ public static final int LEFT = 2; //。。。省略其餘代碼 }
寫法(1)利弊:用到 DefaultValues.DEFAULT_AP 的含義,必須看類裏的註釋,知道他表示中心。若是常量不少的話,把全部的常量都放在這一個接口裏邊,這種方式感受也不是很友好。json
/** * 系統默認值 * */ public class DefaultValues { /** * 默認密碼 */ public static final String DEFAULT_PASSWORD = "000000"; /** * 默認用戶類型 */ public static final String DEFAULT_USER_TYPE = UserType.NormalUser.value(); /** * 默認獲取api名稱 */ public static final String DEFAULT_API = "api"; /** * 默認系統字符編碼 */ public static final String DEFAULT_ENCODING = "UTF-8"; /**集羣規模*/ public static final long CLUSTER_SIZE = 1000; }
寫法(2)利弊:公司的接口常量是在接口裏定義靜態內部類,他能夠把不一樣的功能的常量類進一步分類。把不一樣功能的常量放在了接口的內部類裏,經過不一樣的內部類能夠清楚的知道一個常量的含義。segmentfault
public class Constants { public static class MimeType{ public static final String BIN = "application/octet-stream"; public static final String CSS = "text/css"; public static final String DOC = "application/msword"; public static final String DOCX = ""; public static final String EXE = "application/octet-stream"; public static final String GTAR = "application/x-gtar"; public static final String GZ = "application/x-gzip"; public static final String HTM = "text/html;charset=utf-8"; public static final String ICO = "image/x-icon"; public static final String JPEG = "image/jpeg"; public static final String JPG = "image/jpeg"; public static final String JS = "application/x-javascript;charset=utf-8"; public static final String JSON = "application/json;charset=utf-8"; public static final String FORM = "application/x-www-form-urlencoded; charset=UTF-8"; public static final String MULTIPART = "multipart/form-data; charset=UTF-8"; public static final String MHT = "message/rfc822"; public static final String MHTML = "message/rfc822"; public static final String MOV = "video/quicktime"; public static final String MP3 = "audio/mpeg"; public static final String MPE = "video/mpeg"; public static final String MPEG = "video/mpeg"; public static final String MPG = "video/mpeg"; public static final String PDF = "application/pdf"; public static final String PPT = "application/vnd.ms-powerpoint"; public static final String RTF = "application/rtf"; public static final String SWF = "application/x-shockwave-flash"; public static final String TAR = "application/x-tar"; public static final String TXT = "text/plain;charset=utf-8"; public static final String WAV = "audio/x-wav"; public static final String XML = "text/xml;charset=utf-8"; public static final String ZIP = "application/zip"; } public static class DataState{ public static final String FLAG_REMOVE = "Y"; public static final String FLAG_NORMAL = "N"; } /** * 應用服務器實例運行狀態 */ public static class ServerASInstanceState{ public static final int RUNNING = 1; public static final int SHUT_OFF = 2; } /** * WebServices接口分析 */ public static class WebServicesType{ /**先接收數據,在返回接口狀況的接口 **/ public static final String IN_OUT = "IO"; /**先發數據請求,後返回數據的接口 **/ public static final String OUT_IN = "OI"; /**只發送數據的接口**/ public static final String OUT= "O"; /**只接收數據的接口 **/ public static final String IN = "I"; } /** * 任務調度使用 */ public static class TaskScheduling{ /**任務ID **/ public static final String TASK_ID = "taskID"; /**任務URL **/ public static final String TASK_URI = "taskURI"; /**任務URL **/ public static final String TASK_NAME = "taskName"; /**任務目標服務器IP **/ public static final String TASK_SERVER_IP = "taskServerIp"; /**任務目標服務器IP **/ public static final String TASK_SERVER_PORT = "taskServerPort"; /**任務狀態啓用**/ public static final int TASK_ENABLED = 1; /**任務狀態禁用**/ public static final int TASK_DISABLE = 0; /**每一年任務**/ public static final int TYPE_EVERY_YEAR= 1; /**每個月任務**/ public static final int TYPE_EVERY_MONTH = 2; /**每日任務**/ public static final int TYPE_EVERY_DAY = 3; /**每週任務**/ public static final int TYPE_EVERY_WEEK = 4; /**單次任務**/ public static final int TYPE_SINGLE = 5; } }
雖然有了枚舉,多是因爲設計者習慣問題,還有不少人用的類常量, 定義了類常量,用一個Map<Integer, String>
來封裝常量對應的信息,在static
代碼塊裏,類初始化的時候執行一次put。用的時候 ResponseCode.RESP_INFO.get("DATABASE_EXCEPTION");
就能取出響應信息 因爲項目是先後端分離,在接口文檔裏須要寫上狀態碼,還得寫上狀態碼對應的提示信息,並且咱們的響應類 RespInfo 有message屬性,就是保存常量類裏狀態碼對應的信息的。後端
public class ResponseCode { /** 系統處理正常 */ public static final int SUCCESS_HEAD = 0; /** 系統處理未知異常 */ public static final int EXCEPTION_HEAD = 1; /** JSON解析錯誤 */ public static final int JSON_RESOLVE = 2; /** 類型不匹配 */ public static final int TRANSTYPE_NO = 3; /** Head - messageID未賦值 */ public static final int HEAD_messageID = 4; /** Head - timeStamp未賦值 */ public static final int HEAD_timeStamp = 5; /** Head - messengerID未賦值 */ public static final int HEAD_messengerID = 6; /** Head - transactionType 未賦值 */ public static final int HEAD_transactionType = 7; /** digest校驗不經過 */ public static final int HEAD_DIGEST = 8; /** src校驗不經過 */ public static final int HEAD_SRC_NULL = 10; /** 協議包含非法字符 */ public static final int ILLEGAL_MESSAGE = 11; /** 數據庫異常 */ public static final int DATABASE_EXCEPTION = 9; public static final Map<Integer, String> RESP_INFO = new HashMap<Integer, String>(); static { // Head 相關 RESP_INFO.put(SUCCESS_HEAD, "系統處理正常"); RESP_INFO.put(EXCEPTION_HEAD, "系統處理未知異常"); RESP_INFO.put(JSON_RESOLVE, "JSON解析錯誤"); RESP_INFO.put(TRANSTYPE_NO, "類型不匹配"); RESP_INFO.put(HEAD_messageID, "messageID未賦值"); RESP_INFO.put(HEAD_timeStamp, "timeStamp未賦值"); RESP_INFO.put(HEAD_messengerID, "messengerID未賦值"); RESP_INFO.put(HEAD_transactionType, "transactionType未賦值"); RESP_INFO.put(HEAD_DIGEST, "digest校驗不經過"); RESP_INFO.put(DATABASE_EXCEPTION, "數據庫異常"); RESP_INFO.put(HEAD_SRC_NULL, "src未賦值"); RESP_INFO.put(ILLEGAL_MESSAGE, "協議包含非法字符"); } }
全部的枚舉類都是Enum類的子類,就行Object類同樣,只是沒有寫出來,因此能夠枚舉類可調用Enum的方法。注意是逗號分隔屬性,只有屬性後邊沒有方法的話,最後加不加分號都行。
寫法(1)api
public enum StateType { /** * 成功返回狀態 */ OK(200,"OK"), /** * 請求格式錯誤 */ BAD_REQUEST(400,"bad request"), /** * 未受權 */ UNAUTHORIZED(401,"unauthorized"), /** * 沒有權限 */ FORBIDDEN(403,"forbidden"), /** * 請求的資源不存在 */ NOT_FOUND(404,"not found"), /** * 該http方法不被容許 */ NOT_ALLOWED(405,"method not allowed"), /** * 請求處理髮送異常 */ PROCESSING_EXCEPTION(406,"Handling Exceptions"), /** * * 請求處理未完成 */ PROCESSING_UNFINISHED(407,"To deal with unfinished"), /** * 登陸過時 */ BEOVERDUE(408,"Be overdue"), /** * 用戶未登陸 */ NOT_LOGIN(409,"Not logged in"), /** * 這個url對應的資源如今不可用 */ GONE(410,"gone"), /** * 請求類型錯誤 */ UNSUPPORTED_MEDIA_TYPE(415,"unsupported media type"), /** * 校驗錯誤時用 */ UNPROCESSABLE_ENTITY(422,"unprocessable entity"), /** * 請求過多 */ TOO_MANY_REQUEST(429,"too many request"); private int code; private String value = null; private StateType(int code,String value) { this.code = code; this.value = value; } public String value() { return this.value; } public int getCode() { return code; } public static Boolean isValidateStateType(String... stateType) { for (int i = 0; i < stateType.length; i++) { StateType [] value = StateType.values(); boolean falg = false; for(StateType type : value) { if(type.value.equals(stateType[i])) { falg = true; } } if(!falg) { return falg; } } return true; } } /*使用*/ public static void main(String[] args) { System.out.println("狀態碼:"+StateType.getCode()); System.out.println("錯誤信息:"+StateType.getValue()); }
寫法(2)
public enum Level { /** * 第一層 */ One(1), /** * 第二層 */ Two(2), /** * 第三層 */ Three(3), /** * 第四層 */ Four(4), /** * 第五層 */ Five(5); private int value; Level(int value) { this.value = value; } public int value() { return this.value; } public static Boolean isValidateLevel(int level) { Level [] value = Level.values(); boolean falg = false; for (Level pl : value){ if(pl.value == level){ falg = true; } } return falg; } } /*使用*/ public static void main(String[] args) { System.out.println("樓層:"+Level.Three); }
JDK1.6以前的switch語句只支持int,char,enum類型,使用枚舉,能讓咱們的代碼可讀性更強。
枚舉是聲明一組命名的常數,當一個變量有幾種可能的取值時,能夠將它定義爲枚舉類型。枚舉是將變量的值一一列出來,變量的值只侷限於列舉出來的值的範圍內。
△注意:
枚舉只是枚舉類型,不可以賦值操做。以下:GREEN默認值爲0
,可是GREEN不能=0
,由於數據類型不同。枚舉中變量未直接賦值,默認等於前一個變量值加一,起始值默認爲0。
enum Signal { GREEN, YELLOW, RED } public class TrafficLight { Signal color = Signal.RED; public void change() { switch (color) { case RED: color = Signal.GREEN; break; case YELLOW: color = Signal.RED; break; case GREEN: color = Signal.YELLOW; break; } } }
若是打算自定義本身的方法,那麼必須在enum實例序列的最後添加一個分號(「;」),java中要求必須先定義java實例。
public enum ChannelEnum { MSG_CENTER_CHANNEL1("msg_center_channel1"), MSG_CENTER_CHANNEL("msg_center_channel"); private String channel = null; private ChannelEnum(String channel) { this.channel = channel; } public String getChannel() { return this.channel; } }
public interface Behaviour { void print(); String getInfo(); } public enum Color implements Behaviour{ RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4); // 成員變量 private String name; private int index; // 構造方法 private Color(String name, int index) { this.name = name; this.index = index; } //接口方法 @Override public String getInfo() { return this.name; } //接口方法 @Override public void print() { System.out.println(this.index+":"+this.name); } }
public interface Food { enum Coffee implements Food{ BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO } enum Dessert implements Food{ FRUIT, CAKE, GELATO } }
資料原文地址: