Java中枚舉的實(shí)現(xiàn)與應(yīng)用詳解
前言
Java的枚舉和C/C++中的枚舉作用上類(lèi)似,實(shí)現(xiàn)上不一樣。
本文主要探討下Java中枚舉的實(shí)現(xiàn)與應(yīng)用。
如果要定義常量,可能會(huì)這樣定義:private static final int SUCCESS = 0;一旦這樣的定義多了之后,就很難管理,容易出錯(cuò),甚至重復(fù)定義。用枚舉的話就很簡(jiǎn)潔清晰。
枚舉原理分析
public enum EnumTest { SUCCESS, FAILURE, EXCEPTION }
enum是和class、interface同等級(jí)的關(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é)果反編譯出來(lái)這么多東西。
enum其實(shí)就是實(shí)現(xiàn)了Enum的類(lèi),所以還是先看下Enum這個(gè)類(lèi)。
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { private final String name;//枚舉名稱 private final int ordinal;//序數(shù),從0開(kāi)始算 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(); } }
兩個(gè)主要屬性,name和ordinal。結(jié)合EnumTest反編譯的結(jié)果,初始化時(shí)會(huì)調(diào)用父類(lèi)(Enum)的構(gòu)造方法,將name和ordinal傳進(jìn)去,name是枚舉的名稱,ordinal是聲明的順序(從0開(kāi)始)。
EnumTest中還有一個(gè)VALUES數(shù)組,里面存儲(chǔ)著所有的枚舉實(shí)例,調(diào)用values方法時(shí)返回VALUES數(shù)組的clone。
調(diào)用valueOf方法時(shí),會(huì)調(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í)例的數(shù)組。將枚舉的name作為key,實(shí)例作為value放入map中。valueOf根據(jù)傳入的name從map中取出對(duì)應(yīng)的實(shí)例。
枚舉可以用來(lái)實(shí)現(xiàn)單例,并且是實(shí)現(xiàn)單例的最佳方式。關(guān)于為什么枚舉是單例的最佳實(shí)現(xiàn),參見(jiàn)另一篇博文——幾種單例的對(duì)比。
枚舉應(yīng)用
除了枚舉自身具備的兩個(gè)屬性name和ordinal外,還可以自定義需要的屬性,自定義方法。
public enum EnumTest { SUCCESS(0, "調(diào)用成功"), FAILURE(1, "調(diào)用失敗"), EXCEPTION(-1, "調(diào)用出錯(cuò)"); 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實(shí)際上是繼承了Enum類(lèi),又由于java的單繼承特性,不能再繼承其他類(lèi),但是仍可以通過(guò)別的方式實(shí)現(xiàn)類(lèi)似的功能。
public enum EnumTest { SUCCESS(0, "調(diào)用成功") { @Override String getDesc() { return "恭喜調(diào)用成功"; } }, FAILURE(1, "調(diào)用失敗") { @Override String getDesc() { return "調(diào)用失敗,請(qǐng)重試"; } }, EXCEPTION(-1, "調(diào)用出錯(cuò)") { @Override String getDesc() { return "調(diào)用出錯(cuò)"; } }; 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; } }
或者干脆實(shí)現(xiàn)接口也可以達(dá)到同樣的效果。
到此這篇關(guān)于Java中枚舉的實(shí)現(xiàn)與應(yīng)用詳解的文章就介紹到這了,更多相關(guān)Java枚舉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java中配置ElasticSearch集群環(huán)境賬號(hào)密碼的問(wèn)題
這篇文章主要介紹了Java中配置ElasticSearch集群環(huán)境賬號(hào)密碼的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04在Java Web項(xiàng)目中添加定時(shí)任務(wù)的方法
在Java Web程序中加入定時(shí)任務(wù),這里介紹兩種方式使用監(jiān)聽(tīng)器注入,使用Spring注解@Scheduled注入,需要的朋友可以參考下2018-01-01SpringBoot?實(shí)現(xiàn)流控的操作方法
本文介紹了限流算法的基本概念和常見(jiàn)的限流算法,包括計(jì)數(shù)器算法、漏桶算法和令牌桶算法,還介紹了如何在Spring?Boot中使用Guava庫(kù)和自定義注解以及AOP實(shí)現(xiàn)接口限流功能,感興趣的朋友一起看看吧2024-12-12@MapperScan和@ComponentScan一塊使用導(dǎo)致沖突的解決
這篇文章主要介紹了@MapperScan和@ComponentScan一塊使用導(dǎo)致沖突的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11spring mvc使用@InitBinder標(biāo)簽對(duì)表單數(shù)據(jù)綁定的方法
這篇文章主要介紹了spring mvc使用@InitBinder標(biāo)簽對(duì)表單數(shù)據(jù)綁定的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03mybatisplus添加真正的批量新增、批量更新的實(shí)現(xiàn)
這篇文章主要介紹了mybatisplus添加真正的批量新增、批量更新的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03SpringBoot整合Freemarker實(shí)現(xiàn)頁(yè)面靜態(tài)化的詳細(xì)步驟
這篇文章主要介紹了SpringBoot整合Freemarker實(shí)現(xiàn)頁(yè)面靜態(tài)化,第一步要?jiǎng)?chuàng)建項(xiàng)目添加依賴,本文分步驟給大家詳細(xì)講解,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10