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;//枚舉名稱(chēng)
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是枚舉的名稱(chēng),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-01
SpringBoot?實(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-11
spring 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-03
mybatisplus添加真正的批量新增、批量更新的實(shí)現(xiàn)
這篇文章主要介紹了mybatisplus添加真正的批量新增、批量更新的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
SpringBoot整合Freemarker實(shí)現(xiàn)頁(yè)面靜態(tài)化的詳細(xì)步驟
這篇文章主要介紹了SpringBoot整合Freemarker實(shí)現(xiàn)頁(yè)面靜態(tài)化,第一步要?jiǎng)?chuàng)建項(xiàng)目添加依賴(lài),本文分步驟給大家詳細(xì)講解,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10

