假如有一筆業(yè)務(wù)需要審核尖淘,審核狀態(tài)分:未審核萍摊,審核中当凡,審核通過(guò)山害,審核不通過(guò)。我們?cè)诔绦蚶锸欠窨梢灾苯舆@么寫(xiě):
if(state==1){//1代表未操作
????? //操作
}else{
???? //......
}
將狀態(tài)標(biāo)識(shí)直接寫(xiě)在代碼里面(硬編碼)沿量,只圖一時(shí)方便浪慌,卻是后患無(wú)窮,如果有一天你需要修改狀態(tài)標(biāo)識(shí)朴则,用0代表未審核而不是1权纤,你不得不將所有與該標(biāo)識(shí)相關(guān)的代碼都找出來(lái)一個(gè)個(gè)改,另外乌妒,在編碼過(guò)程中汹想,標(biāo)識(shí)輸入錯(cuò)誤的概率是比較高的,一不小心把0輸入成了10撤蚊,雖然不會(huì)提示任何編譯錯(cuò)誤古掏,但運(yùn)行結(jié)果將是出乎人的意料的。
于是我們很快想到可以用常量代替:
public static final int UNAUDIT = 0;
相關(guān)判斷代碼則是:
if(state==CONSTANT.UNAUDIT){
????? //操作
}else{
????? //......
}
這段代碼比硬編碼更加健壯容易維護(hù)侦啸,但是仍然有不足之處槽唾。
1、UNAUDIT是編譯期常量光涂,如果其值被改變庞萍,那么使用方需要重新編譯。
2忘闻、沒(méi)有簡(jiǎn)便的方法獲取標(biāo)識(shí)代表的字符串描述钝计。
于是我們用枚舉類來(lái)代替常量。
public enum AuditState {
???? UNAUDIT(1),
???? AUDITING(2),
???? AUDIT_SUCCESS(3),
???? AUDIT_FAIL(4);
private final int statenum;
??? AuditState(int statenum){
?? this.statenum = statenum;
}
public int getStatenum() {
??? return statenum;
}
}
調(diào)用如下:
if (state == AuditState.UNAUDIT.getStatenum()) {
??? //AuditState.UNAUDIT.toString()獲取字符串描述
System.out.println(
???? AuditState.UNAUDIT.toString() + "標(biāo)識(shí)是 "
??? + AuditState.UNAUDIT.getStatenum());
} else {
?? //......
}
枚舉類還有更加強(qiáng)大的功能齐佳,如添加字段葵蒂,方法,還可以對(duì)他進(jìn)行遍歷訪問(wèn)
一重虑、分析?
常量的聲明是每一個(gè)項(xiàng)目中不可或缺的践付,在Java1.5之前,我們只有兩種方式的聲明:類常量和接口常量缺厉。不過(guò)永高,在1.5版之后有了改進(jìn)隧土,即新增了一種常量聲明方式,枚舉常量命爬。代碼如下:?
enum Season{
? ? Spring,Summer,Autumn,Winter;
}
二曹傀、場(chǎng)景?
那么枚舉常量與我們的經(jīng)常使用的類常量和靜態(tài)常量比有什么優(yōu)勢(shì)呢??
1.枚舉常量更簡(jiǎn)單?
先把Season枚舉翻譯成接口饲宛,代碼如下:?
interface Season{
? ? int Sprint = 0;
? ? int Summer = 1;
? ? int Autumn = 2;
? ? int Winter = 3;
}
枚舉只需要定義每個(gè)枚舉項(xiàng)皆愉,不需要定義枚舉值,而接口常量(或類常量)則必須定義值艇抠,否則編譯通不過(guò)幕庐;兩個(gè)引用的方式相同(都是“類名.屬性”,如Season.Sprint)家淤,但是枚舉表示的是一個(gè)枚舉項(xiàng)异剥,字面含義是春天,而接口常量卻是一個(gè)Int類型絮重。?
2.枚舉常量屬于穩(wěn)態(tài)型?
使用常量接口冤寿,我們得對(duì)輸入值進(jìn)行檢查,確定是否越界青伤,如果常量非常龐大督怜,校驗(yàn)輸入就是一件非常麻煩的事情,但這是一個(gè)不可逃避的過(guò)程狠角。?
public void describe(int s){
? ? //s變量不能超越邊界亮蛔,校驗(yàn)條件
? ? if(s >= 0 && s <4){
? ? ? ? switch(s){
? ? ? ? ? ? case Season.Summer:
? ? ? ? ? ? ? ? System.out.println("Summer is very hot!");
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case Season.Winter:
? ? ? ? ? ? ? ? System.out.println("Winter is very cold!");
? ? ? ? ? ? ? ? break;
? ? ? ? …..
? ? ? ? }
? ? }
}
我們?cè)賮?lái)看看枚舉常量是否能夠避免校驗(yàn)問(wèn)題,代碼如下:
public void describe(Season s){
? ? switch(s){
? ? ? ? case Season.Summer:
? ? ? ? ? ? System.out.println("Summer is very hot!");
? ? ? ? ? ? break;
? ? ? ? case Season.Winter:
? ? ? ? ? ? System.out.println("Winter is very cold!");
? ? ? ? ? ? break;
? ? ? ? …...
? ? }
}
不用校驗(yàn)擎厢,已經(jīng)限定了是Season枚舉,所以只能是Season類的四個(gè)實(shí)例辣吃。這也是我們看重枚舉的地方:在編譯期間限定類型动遭,不允許發(fā)生越界的情況。
3.枚舉具有內(nèi)置方法?
每個(gè)枚舉都是java.lang.Enum的子類神得,該基類提供了諸如獲得排序值的ordinal方法厘惦、compareTo比較方法等,大大簡(jiǎn)化了常量的訪問(wèn)哩簿。比如宵蕉,列出所有枚舉值:?
public static void main(String[] args){
? ? for(Season s:Season.values()){
? ? ? ? System.out.println(s);
? ? }
}
4.枚舉可以自定義方法?
這一點(diǎn)似乎不是枚舉的優(yōu)點(diǎn),類常量也可以有自己的方法节榜,但關(guān)鍵是枚舉常量不僅僅可以定義靜態(tài)方法羡玛,還可以定義非靜態(tài)方法,而且還能夠從根本上杜絕常量類被實(shí)例化宗苍。比如我們?cè)诙x獲取最舒服的季節(jié)稼稿,使用枚舉的代碼如下:?
enum Season{
? ? Spring,Summer,Autumn,Winter;
? ? //最舒服的季節(jié)
? ? public static Season getComfortableSeason(){
? ? ? ? return Spring;
? ? }
}
那如果是使用類常量如何實(shí)現(xiàn)呢薄榛?如下:?
class Season{
? ? public final static int Spring = 0;
? ? public final static int Summer = 1;
? ? public final static int Autumn = 2;
? ? public final static int Winter = 3;
? ? //最舒服的季節(jié)
? ? public static int getComfortableSeason(){
? ? ? ? return Spring;
? ? }
}
雖然枚舉在很多方面都比接口常量和類常量好用,但是它有一點(diǎn)比不上接口常量和類常量的让歼,就是繼承敞恋,枚舉類型是不能有繼承的,也就是說(shuō)一個(gè)枚舉常量定義完畢后谋右,除非修改重構(gòu)硬猫,否則無(wú)法做擴(kuò)展。?
三改执、建議?
在項(xiàng)目開(kāi)發(fā)中啸蜜,推薦使用枚舉常量代替接口常量或類常量。?