枚举举例
1. 在J2SE5.0中要定義枚舉類型是使用enum關鍵詞,枚舉類型主要提供一些常數。如下列代碼定義了Action枚舉類型:
Java代碼
public enum Action
{
TURN_LEFT,
TURN_RIGHT,
SHOOT
}
在Action.java中編寫此段代碼并編譯,雖然語法上不像是在定義類,但枚舉類型本質上就是一個類。所以編譯完成后,會產生一個Action.class文件。
下面的代碼是說明如何使用定義好的枚舉類型一個示例:
Java代碼
public class EnumDemo
{
public static void main(String[] args)
{
doAction(Action.TURN_RIGHT);
}
public static void doAction(Action action)
{
switch(action)
{
case TURN_LEFT:
System.out.println("向左轉");
break;
case TURN_RIGHT:
System.out.println("向右轉");
break;
case SHOOT:
System.out.println("射擊");
break;
}
}
}
運行結果:向右轉。其中doAction()方法所接受的變量必須是Action枚舉類型,如果對此方法輸入其他類型的變量,編譯器會報告錯誤。另外,如果在上面的switch中加入了不屬于Action中枚舉的值,編譯器也會報告錯誤。例如:在上面代碼case SHOOT段下面再加上以下代碼:
case STOP:
System.out.println("STOP");
break;
則在編譯時編譯器會顯示以下錯誤:
unqualified enumeration constant name required
case STOP:
^
2. 可以在一個獨立的文件中聲明枚舉值,或是在某個類中聲明枚舉成員。例如:
Java代碼
public class EnumDemo2
{
private enum InnerAction {TURN_LEFT,TURN_RIGHT,SHOOT};
public static void main(String[] args)
{
doAction(InnerAction.TURN_RIGHT);
}
public static void doAction(InnerAction action)
{
switch(action)
{
case TURN_LEFT:
System.out.println("向左轉");
break;
case TURN_RIGHT:
System.out.println("向右轉");
break;
case SHOOT:
System.out.println("射擊");
break;
}
}
}
由于枚舉類型本質上還是類,所以這段代碼中枚舉聲明方式有些像在聲明內嵌類。在編譯完EnumDemo2.java后,會有一些額外的 .class文件產生,在此例中就是EnumDemo2$InnerAction.class與EnumDemo2$1.class。看到這兩個文件,就可以知道實際上編譯器產生了成員內部類和匿名內部類。
上面通過枚舉類型設定常數的方式比舊版本的常數設定方式多了編譯時期類型檢查的好處。以下將深入討論枚舉類型的一些知識,以便深入理解。
2. 深入枚舉類型:
定義枚舉類型其實就是在定義一個類,只不過很多細節由編譯器幫你補齊了,所以,某種程度上enum關鍵詞的作用就像是class或interface.
當使用enum定義枚舉類型時,實際上所定義出來的類型是繼承自java.lang.Enum類。而每個被枚舉的成員其實就是定義的枚舉類型的一個實例,它們都被默認為final。無法改變常數名稱所設定的值,它們也是public和static的成員,這與接口中的常量限制相同。可以通過類名稱直接使用它們。
如1中所定義的枚舉類型Action,TURN_LEFT,TURN_RIGHT,SHOOT都是Action的一個對象實例。因為是對象,所以,對象上自然有一些方法可以調用。如從Object繼承焉的toString()方法被重新定義了,可以讓你直接取得枚舉值的字符串描述;values()方法可以讓您取得所有的枚舉成員實例,并以數組方式返回。您可以使用這兩個方法來簡單的將Action的枚舉成員顯示出來。靜態valueOf()方法可以讓您將指定的字符串嘗試轉換為枚舉類型。可以用compareTo()方法來比較兩個枚舉對象在枚舉時的順序。-1之前,0位置相同,1之后。對于每個枚舉成員,使用ordinal()方法,依枚舉順序得到位置索引,默認以0開始。
3.枚舉上的方法:定義枚舉類型基本上就是在定義類,定義枚舉類型時也可以定義方法。如可以為枚舉加上一些描述,而不是使用默認的toString()返回值來描述枚舉值。如下代碼所示:
Java代碼
public enum DetailAction
{
TURN_LEFT,TURN_RIGHT,SHOOT;
public String getDescription()
{
switch(this.ordinal())
{
case 0:
return "向左轉";
case 1:
return "向右轉";
case 2:
return "射擊";
default:
return??? null;
}
}
}
可以用下面的代碼測試所定義的方法是否可用。
Java代碼
public class DetailActionDemo
{
public static void main(String[] args)
{
for(DetailAction action : DetailAction.values())
{
System.out.printf("%s: %s%n",action,action.getDescription());
}
}
}
運行結果:
TURN_LEFT: 向左轉
TURN_RIGHT: 向右轉
SHOOT: 射擊
4.枚舉類型既然是類,那么也就可以有構造函數。只不過不得有公開(Public)的構造函數,這是為了避免直接對枚舉類型實例化。如下代碼:
Java代碼
enum DetailActioin2
{
TURN_LEFT("向左轉"),TURN_RIGHT("向右轉"),SHOOT("射擊");
private String description;
//不公開的構造函數
private DetailActioin2(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
}
非公開的構造函數最常見的一個例子就是singleton模式的應用,當某個類只能有一個實例時,可由類維護唯一的實例,這時可以將構造函數設定為私有,取用此類的開發人員就不能自行新增多個實例了。Singleton模式的簡易版本代碼如下:
Java代碼
public class Singleton
{
//構造函數私有,只限內部調用
private SingleTon(){};
private static Singleton instance = null;
public static synchronized SingleTon getInstance()
{
if(instance == null)
instance = new Singleton();
return instance;
}
}
4. 因值而異的類實現(Value-Specific Class Bodies)
這個功能簡單地說像是在使用匿名內部類來實現Command模式,它可以為每個枚舉值定義各自的類本體與方法實現。
一種實現方式如下:
Java代碼
public interface IDescription
{
public String getDescription();
}
public enum MoreAction implements IDescription
{
TURN_LEFT
{
//實現接口上的方法
public String getString() {return "向左轉"}
}, //注意這里的枚舉值分隔使用,
TURN_RIGHT
{
//實現接口上的方法
public String getString() {return "向右轉"}
}, //注意這里的枚舉值分隔使用,
SHOOT
{
//實現接口上的方法
public String getString() {return "射擊"}
}; //注意這里的枚舉值結束使用;
}
每個枚舉成員的{與}之間是類本體,還可以在其中如同定義類一樣地聲明數據成員或者數據方法。測試這段代碼的程序如下:
Java代碼
public class MoreActionDemo
{
public static void main(String[] args)
{
for(MoreAction action : MoreAction.values())
{
System.out.printf("%s: %s%n",action,action.getDescription());
}
}
}
這個例子是將因值而異的類實現用在返回枚舉值的描述上,可以按照相同的方式,為每個枚舉值加上一些各自的方法實現,而調用的接口是統一的。執行結果如下:
D:\Java_Test>javac IDescription.java
D:\Java_Test>javac MoreAction.java
D:\Java_Test>javac MoreActionDemo.java
D:\Java_Test>java MoreActionDemo
TURN_LEFT: 向左轉
TURN_RIGHT: 向右轉
SHOOT: 射擊
可能是利用枚舉類型實現的接口中的方法,這里直接用
D:\Java_Test>javac IDescription.java 編譯時會提示找不到getDescription()方法,所以,只好挨個來編譯了。
也可以運用抽象方法去改寫上面的MoreAction.java,如下:
Java代碼
public enum MoreAction2
{
TURN_LEFT{
//實現抽象方法
public String getDescription()
{
return "向左轉";
}
}, //記得這里的枚舉值分隔使用,
TURN_RIGHT{
//實現抽象方法
public String getDescription()
{
return "向右轉";
}
},
SHOOT{
//實現抽象方法
public String getDescription()
{
return "射擊";
}
}; //記得這里的枚舉值結束使用;
//聲明抽象方法
public abstract String getDescription();
}
執行結果與上面相同。
?
?
?
下面是枚舉的而一個綜合例子
public?class?TestEnum?{
????/*最普通的枚舉*/
????public?enum?ColorSelect?{
????????red,?green,?yellow,?blue;????
????}
????/*?枚舉也可以象一般的類一樣添加方法和屬性,你可以為它添加靜態和非靜態的屬性或方法,這一切都象你在一般的類中做的那樣.?*/
????public?enum?Season?{
????????//?枚舉列表必須寫在最前面,否則編譯出錯
????????winter,?spring,?summer,?fall;
????????private?final?static?String?location?=?"Phoenix";????????
????????public?static?Season?getBest()?{
????????????if?(location.equals("Phoenix"))
????????????????return?winter;
????????????else
????????????????return?summer;
????????}
????}
????/*還可以有構造方法*/
????public?enum?Temp?{
????????/*通過括號賦值,而且必須有帶參構造器和一屬性跟方法,否則編譯出錯
?????????*?賦值必須是都賦值或都不賦值,不能一部分賦值一部分不賦值
?????????*?如果不賦值則不能寫構造器,賦值編譯也出錯*/
????????absoluteZero(-459),?freezing(32),boiling(212),?paperBurns(451);
????????
????????private?final?int?value;
????????public?int?getValue()?{
????????????return?value;
????????}
????????//構造器默認也只能是private, 從而保證構造函數只能在內部使用
????????Temp(int?value)?{
????????????this.value?=?value;
????????}
????}
????public?static?void?main(String[]?args)?{
????????/*
?????????*?枚舉類型是一種類型,用于定義變量,以限制變量的賦值?賦值時通過"枚舉名.值"來取得相關枚舉中的值
?????????*/
????????ColorSelect?m?=?ColorSelect.blue;
????????switch?(m)?{
????????/*注意:枚舉重寫了ToString(),說以枚舉變量的值是不帶前綴的
??????????*所以為blue而非ColorSelect.blue
????????? */
?case?red:
????????????System.out.println("color?is?red");
????????????break;
????????case?green:
????????????System.out.println("color?is?green");
????????????break;
????????case?yellow:
????????????System.out.println("color?is?yellow");
????????????break;
????????case?blue:
????????????System.out.println("color?is?blue");
????????????break;
????????}
????????System.out.println("遍歷ColorSelect中的值");
????????/*通過values()獲得枚舉值的數組*/
????????for?(ColorSelect?c?:?ColorSelect.values())?{
????????????System.out.println(c);
????????} ?
System.out.println("枚舉ColorSelect中的值有:"+ColorSelect.values().length+"個");
? /*ordinal()返回枚舉值在枚舉中的索引位置,從0開始*/
System.out.println(ColorSelect.red.ordinal());//0
System.out.println(ColorSelect.green.ordinal());//1
System.out.println(ColorSelect.yellow.ordinal());//2
System.out.println(ColorSelect.blue.ordinal());//3
/*枚舉默認實現了java.lang.Comparable接口*/?
System.out.println(ColorSelect.red.compareTo(ColorSelect.green));
System.out.println(Season.getBest());
????????
????????for(Temp?t:Temp.values()){
????????????/*通過getValue()取得相關枚舉的值*/
????????????System.out.println(t+"的值是"+t.getValue());
????????}
????}
}
?
?
?
轉載于:https://www.cnblogs.com/shenliang123/archive/2011/10/27/2226912.html
總結
- 上一篇: C陷阱与缺陷代码分析之第2章语法陷阱
- 下一篇: 深入浅出asterisk(一):aste