枚舉類
使用場(chǎng)景:一個(gè)類的對(duì)象固定且有限(一般用來(lái)定義返回碼、狀態(tài)碼)
產(chǎn)生原因:有明確的意義,固定且不能被更改(比static final設(shè)定強(qiáng)而且安全)
定義:使用 enum關(guān)鍵字,跟定義一個(gè)類相同,枚舉類是一種特殊的類。第一行定義的是實(shí)例,使用逗號(hào)分隔。
public enum EnumDemo1 {
SPRING,SUMMER,WINTER;
}
特征
- 父類是java.lang.Enum類,不能繼承其他類,間接實(shí)現(xiàn)了java.lang.Serializable和java.lang.Comparable接口
- 定義的非抽象枚舉類,默認(rèn)是final類,其定義的實(shí)例對(duì)象也均是public static final
- 其構(gòu)造器必須是private,如果沒(méi)有顯示指定默認(rèn)也是private
- 其所有實(shí)例必須在第一行顯示指定,否則該枚舉類永遠(yuǎn)不能產(chǎn)生實(shí)例
遍歷枚舉實(shí)例
// 枚舉類默認(rèn)提供了一個(gè)values()方法,可以用來(lái)迭代獲取枚舉實(shí)例
public enum EnumDemo1 {
SPRING,SUMMER,WINTER;
public static void main(String[] args) {
for (EnumDemo1 obj : EnumDemo1.values()) {
System.out.println(obj);
}
}
}
Enum API詳解
-
int compareTo(E o):比較枚舉實(shí)例的順序,定義在對(duì)象o前面返回的是負(fù)值,在對(duì)象o之后返回正值。說(shuō)人話(enum1.compareTo(enum2) 返回值為 ==enum1的索引值 - enum2的索引值 + 1==)
System.out.println(SPRING.compareTo(SUMMER)); // -1 String name():返回枚舉值的名稱
String toString():返回枚舉值的名稱,同name方法的作用是一樣的,源碼二者均是返回的name
int ordinal():返回枚舉值的索引值,第一個(gè)默認(rèn)是0
readObject(ObjectInputStream in)和readObjectNoData(),保證常量實(shí)例唯一, 重寫覆蓋默認(rèn)序列化規(guī)則
參考:https://stackoverflow.com/questions/34589325/why-default-serialization-is-prevented-in-enum-class
- public static<T extends Enum<T>> T valueOf(Class<T> enumType,String name):返回指定枚舉類中指定名稱的枚舉值
System.out.println(Enum.valueOf(EnumDemo1.class,"SPRING"));
抽象枚舉類
抽象枚舉類不需要使用abstract顯示聲明,里面定義一個(gè)抽象方法就表示該枚舉類是一個(gè)抽象枚舉類,與普通抽象類相似
public enum EnumDemo3{
OK{
@Override
public void info() {
// todo
}
};
public abstract void info();
}
編譯后發(fā)現(xiàn),系統(tǒng)會(huì)自動(dòng)給它添加abstract,同時(shí)生成一個(gè)OK的匿名class
Compiled from "EnumDemo3.java"
public abstract class enumdemo.EnumDemo3 extends java.lang.Enum<enumdemo.EnumDemo3> {
public static final enumdemo.EnumDemo3 OK;
public static enumdemo.EnumDemo3[] values();
Code:
0: getstatic #2 // Field $VALUES:[Lenumdemo/EnumDemo3;
3: invokevirtual #3 // Method "[Lenumdemo/EnumDemo3;".clone:()Ljava/lang/Object;
6: checkcast #4 // class "[Lenumdemo/EnumDemo3;"
9: areturn
實(shí)際使用
原先的項(xiàng)目組里面是使用一個(gè)Constant類定義整個(gè)項(xiàng)目里面常用的常量和返回碼、錯(cuò)誤碼、業(yè)務(wù)碼,挺亂的而且容易忘記還需要經(jīng)常維護(hù)查看對(duì)應(yīng)的業(yè)務(wù)信息。
后面升級(jí)就使用了枚舉類進(jìn)行改造,定義一個(gè)接口控制總的行為,根據(jù)具體的功能和業(yè)務(wù)去實(shí)現(xiàn)對(duì)應(yīng)的常量信息。
后面項(xiàng)目組解散換了一個(gè)古老的項(xiàng)目,它把編碼放在一個(gè)常量類里面,然后定義的變量和對(duì)應(yīng)的業(yè)務(wù)文字描述用一個(gè)鍵值對(duì)的方式放在一個(gè)code.properties文件里面(坑爹)。重點(diǎn)是這個(gè)文件的格式是ANSI,使用eclipse會(huì)自動(dòng)把漢字解析出來(lái),但是我用的是idea尼瑪全是一堆16進(jìn)制字符,整的我沒(méi)脾氣了,問(wèn)了項(xiàng)目組的人咋個(gè)設(shè)計(jì)成這個(gè)樣子(遺留問(wèn)題,不曉得,吐血)。
idea中自動(dòng)將ANSI中的數(shù)據(jù)解析設(shè)置:settings ----> Editor ----> File Encodings ----> 勾選 Transparent native-to-ascii conversion。
這樣弄我沒(méi)感覺(jué)到有什么優(yōu)勢(shì),每次使用都要根據(jù)key去文件里面拿一邊特別不方便,查對(duì)應(yīng)的業(yè)務(wù)編碼信息的時(shí)候還需要去找到這個(gè)文件然后在find一下,感覺(jué)有種腦子被門夾的感覺(jué)。
改造
public interface EnumPower {
public String getCode();
public String getMessage();
}
public enum ReturnCode implements EnumPower{
SUCCESS("0","成功"),
FAIL("1","失敗");
private final String code = null;
private final String message = null;
private static Hashtable<String, ReturnCode> aliasEnums;
ReturnCode(String code, String message) {
this.code = code;
this.message = message;
this.init(code, message);
}
private void init(String code, String message) {
synchronized (this.getClass()) {
if (aliasEnums == null) {
aliasEnums = new Hashtable<String, ReturnCode>();
}
}
aliasEnums.put(code, this);
aliasEnums.put(message, this);
}
public static ReturnCode valueOfAlias(String alias) {
return aliasEnums.get(alias);
}
public static ReturnCode valueOfAlias(char alias) {
return aliasEnums.get(String.valueOf(alias));
}
@Override
public String getCode() {
return this.code;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public String toString() {
return this.getMessage() + "〔信息代碼:" + this.getCode() + "〕";
}
}
總結(jié):
? 系統(tǒng)會(huì)為枚舉類自動(dòng)創(chuàng)建里面定義好的實(shí)例,因此它的構(gòu)造方法必須是private。
? 枚舉類也是類,所以構(gòu)造方法里面也可以帶參數(shù),它的特性就決定了它能夠自帶業(yè)務(wù)信息在里面
? 不好的一點(diǎn)是不能通過(guò)定義的實(shí)例反向定位被調(diào)用的地方,只能通過(guò)搜索SUCCESS來(lái)確定,所以一般定義之后不要去改,否則你又不確定改完之后所有調(diào)用的地方都符合你要的業(yè)務(wù)就會(huì)有問(wèn)題。