Java中枚舉的實現(xiàn)與應用詳解
前言
Java的枚舉和C/C++中的枚舉作用上類似,實現(xiàn)上不一樣。
本文主要探討下Java中枚舉的實現(xiàn)與應用。
如果要定義常量,可能會這樣定義:private static final int SUCCESS = 0;一旦這樣的定義多了之后,就很難管理,容易出錯,甚至重復定義。用枚舉的話就很簡潔清晰。
枚舉原理分析
public enum EnumTest { SUCCESS, FAILURE, EXCEPTION }
enum是和class、interface同等級的關(guān)鍵字,那么它有什么特殊的地方呢?遇事不決看源碼。。。反編譯看下上面的代碼
public final class EnumTest extends Enum { public static EnumTest[] values() { return (EnumTest[])$VALUES.clone(); } public static EnumTest valueOf(String s) { return (EnumTest)Enum.valueOf(com/brain/demo/enumtest/EnumTest, s); } private EnumTest(String s, int i) { super(s, i); } public static final EnumTest SUCCESS; public static final EnumTest FAILURE; public static final EnumTest EXCEPTION; private static final EnumTest $VALUES[]; static { SUCCESS = new EnumTest("SUCCESS", 0); FAILURE = new EnumTest("FAILURE", 1); EXCEPTION = new EnumTest("EXCEPTION", 2); $VALUES = (new EnumTest[] { SUCCESS, FAILURE, EXCEPTION }); } }
枚舉里只有三行,結(jié)果反編譯出來這么多東西。
enum其實就是實現(xiàn)了Enum的類,所以還是先看下Enum這個類。
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { private final String name;//枚舉名稱 private final int ordinal;//序數(shù),從0開始算 protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } public String toString() { return name; } public final boolean equals(Object other) { return this==other; } protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }
兩個主要屬性,name和ordinal。結(jié)合EnumTest反編譯的結(jié)果,初始化時會調(diào)用父類(Enum)的構(gòu)造方法,將name和ordinal傳進去,name是枚舉的名稱,ordinal是聲明的順序(從0開始)。
EnumTest中還有一個VALUES數(shù)組,里面存儲著所有的枚舉實例,調(diào)用values方法時返回VALUES數(shù)組的clone。
調(diào)用valueOf方法時,會調(diào)用Enum的valueOf方法
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException( "No enum constant " + enumType.getCanonicalName() + "." + name); } //Class.java Map<String, T> enumConstantDirectory() { if (enumConstantDirectory == null) { T[] universe = getEnumConstantsShared(); if (universe == null) throw new IllegalArgumentException( getName() + " is not an enum type"); Map<String, T> m = new HashMap<>(2 * universe.length); for (T constant : universe) m.put(((Enum<?>)constant).name(), constant); enumConstantDirectory = m; } return enumConstantDirectory; } T[] getEnumConstantsShared() { if (enumConstants == null) { if (!isEnum()) return null; try { final Method values = getMethod("values"); java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { values.setAccessible(true); return null; } }); @SuppressWarnings("unchecked") T[] temporaryConstants = (T[])values.invoke(null); enumConstants = temporaryConstants; } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { return null; } } return enumConstants; }
追著源碼一層層調(diào)用,最后還是調(diào)用values方法,拿到包含所有枚舉實例的數(shù)組。將枚舉的name作為key,實例作為value放入map中。valueOf根據(jù)傳入的name從map中取出對應的實例。
枚舉可以用來實現(xiàn)單例,并且是實現(xiàn)單例的最佳方式。關(guān)于為什么枚舉是單例的最佳實現(xiàn),參見另一篇博文——幾種單例的對比。
枚舉應用
除了枚舉自身具備的兩個屬性name和ordinal外,還可以自定義需要的屬性,自定義方法。
public enum EnumTest { SUCCESS(0, "調(diào)用成功"), FAILURE(1, "調(diào)用失敗"), EXCEPTION(-1, "調(diào)用出錯"); private int status; private String msg; EnumTest(int status, String msg) { this.status = status; this.msg = msg; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getDesc() { return status + ":" + msg; } public static void main(String[] args) { System.out.println(EnumTest.FAILURE.getDesc());//1:調(diào)用失敗 } }
由于enum實際上是繼承了Enum類,又由于java的單繼承特性,不能再繼承其他類,但是仍可以通過別的方式實現(xiàn)類似的功能。
public enum EnumTest { SUCCESS(0, "調(diào)用成功") { @Override String getDesc() { return "恭喜調(diào)用成功"; } }, FAILURE(1, "調(diào)用失敗") { @Override String getDesc() { return "調(diào)用失敗,請重試"; } }, EXCEPTION(-1, "調(diào)用出錯") { @Override String getDesc() { return "調(diào)用出錯"; } }; private int status; private String msg; EnumTest(int status, String msg) { this.status = status; this.msg = msg; } abstract String getDesc(); public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
或者干脆實現(xiàn)接口也可以達到同樣的效果。
到此這篇關(guān)于Java中枚舉的實現(xiàn)與應用詳解的文章就介紹到這了,更多相關(guān)Java枚舉內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java中配置ElasticSearch集群環(huán)境賬號密碼的問題
這篇文章主要介紹了Java中配置ElasticSearch集群環(huán)境賬號密碼的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04@MapperScan和@ComponentScan一塊使用導致沖突的解決
這篇文章主要介紹了@MapperScan和@ComponentScan一塊使用導致沖突的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11spring mvc使用@InitBinder標簽對表單數(shù)據(jù)綁定的方法
這篇文章主要介紹了spring mvc使用@InitBinder標簽對表單數(shù)據(jù)綁定的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03mybatisplus添加真正的批量新增、批量更新的實現(xiàn)
這篇文章主要介紹了mybatisplus添加真正的批量新增、批量更新的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03SpringBoot整合Freemarker實現(xiàn)頁面靜態(tài)化的詳細步驟
這篇文章主要介紹了SpringBoot整合Freemarker實現(xiàn)頁面靜態(tài)化,第一步要創(chuàng)建項目添加依賴,本文分步驟給大家詳細講解,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10