Java中枚舉的實(shí)現(xiàn)與應(yīng)用詳解
前言
Java的枚舉和C/C++中的枚舉作用上類似,實(shí)現(xiàn)上不一樣。
本文主要探討下Java中枚舉的實(shí)現(xiàn)與應(yīng)用。
如果要定義常量,可能會這樣定義:private static final int SUCCESS = 0;一旦這樣的定義多了之后,就很難管理,容易出錯(cuò),甚至重復(fù)定義。用枚舉的話就很簡潔清晰。
枚舉原理分析
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其實(shí)就是實(shí)現(xiàn)了Enum的類,所以還是先看下Enum這個(gè)類。
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();
}
}兩個(gè)主要屬性,name和ordinal。結(jié)合EnumTest反編譯的結(jié)果,初始化時(shí)會調(diào)用父類(Enum)的構(gòu)造方法,將name和ordinal傳進(jìn)去,name是枚舉的名稱,ordinal是聲明的順序(從0開始)。
EnumTest中還有一個(gè)VALUES數(shù)組,里面存儲著所有的枚舉實(shí)例,調(diào)用values方法時(shí)返回VALUES數(shù)組的clone。
調(diào)用valueOf方法時(shí),會調(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中取出對應(yīng)的實(shí)例。
枚舉可以用來實(shí)現(xiàn)單例,并且是實(shí)現(xiàn)單例的最佳方式。關(guān)于為什么枚舉是單例的最佳實(shí)現(xiàn),參見另一篇博文——幾種單例的對比。
枚舉應(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類,又由于java的單繼承特性,不能再繼承其他類,但是仍可以通過別的方式實(shí)現(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)用出錯(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot定時(shí)任務(wù)調(diào)度與爬蟲的配置實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot定時(shí)任務(wù)調(diào)度與爬蟲的實(shí)現(xiàn),使用webmagic開發(fā)爬蟲,繼承PageProcessor接口編寫自己的處理類,process是定制爬蟲邏輯的核心接口,在這里編寫抽取邏輯,具體實(shí)現(xiàn)配置過程跟隨小編一起看看吧2022-01-01
Java編程中使用throw關(guān)鍵字拋出異常的用法簡介
這篇文章主要介紹了Java編程中使用throw關(guān)鍵字拋出異常的用法,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-11-11
Java高級用法中的JNA類型映射注意細(xì)節(jié)及使用問題
本文介紹了在使用JNA方法映射中應(yīng)該注意的一些細(xì)節(jié)和具體的使用問題,對java??JNA類型映射注意細(xì)節(jié)感興趣的朋友一起看看吧2022-04-04
idea創(chuàng)建maven項(xiàng)目速度慢的三種解決方案
這篇文章主要介紹了idea創(chuàng)建maven項(xiàng)目速度慢的三種解決方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
Java執(zhí)行hadoop的基本操作實(shí)例代碼
這篇文章主要介紹了Java執(zhí)行hadoop的基本操作實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04

