190 likes | 385 Views
第十四章 Enum 類別的使用. 14-1 使用 static 和 final 設計列舉資料 14-2 使用 enum 關鍵字設計列舉資料 14-3 使用 Enum 類別 14-4 使用 EnumMap 類別 14-5 使用 EnumSet 類別. 14-1 使用 static 和 final 設計列舉資料. 列舉可以視為是一整組相關資料的一覽表,它是程式設計時常會用到資料結構。 列舉型式資料的使用是為了讓我們在設計程式時,能更清楚及更方便的表達資料的意義。
E N D
第十四章 Enum類別的使用 • 14-1 使用static和final設計列舉資料 • 14-2 使用enum關鍵字設計列舉資料 • 14-3使用Enum類別 • 14-4 使用EnumMap類別 • 14-5 使用EnumSet類別
14-1 使用static和final設計列舉資料 • 列舉可以視為是一整組相關資料的一覽表,它是程式設計時常會用到資料結構。 • 列舉型式資料的使用是為了讓我們在設計程式時,能更清楚及更方便的表達資料的意義。 • 為了讓列舉常數的值不被更改,我們會使用final來設計列舉常數。而為了使用上的方便,列舉常數都會使用了static修飾子。而且,某個列舉常數會代表某一個整數值。 • 因此,列舉常會被設計成: class Season { public static final int SPRING = 0; public static final int SUMMER = 1; public static final int AUTUMN = 2; public static final int WINTER = 3; }
14-1 使用static和final設計列舉資料 • 在使用列舉常數時,我們會以「類別名稱.常數名稱」的方式來使用列舉常數,例如: System.out.println(Season.SPRING); • 由於列舉常數是代表一個int的值,為了讓列舉常數的顯示能更符合user friendly的要求,我們會利用陣列來對應某個列舉常數所要表達的意涵。因此,列舉的宣告通常會變成: class Season { public static final int SPRING = 0; public static final int SUMMER = 1; public static final int AUTUMN = 2; public static final int WINTER = 3; public static final String[] showSeason = {"春天", "夏天", "秋天", "冬天"}; } • 如果要顯示某個列舉常數的特別意涵時,我們會這樣子使用: System.out.println(Season.showSeason[Season.SPRING]);
14-1 使用static和final設計列舉資料 • 這樣的使用方式其實會有一些缺點存在。第一項缺點是資料維護的不易。 • 由於程式中使用了陣列來代表每個列舉常數所要顯示的內容,一旦程式中需要變更列舉常數的順序,或是要在列舉常數中插入一個新的常數時,這樣的設計方式會讓程式在修改時,需要花費更大的精神。 • 第二項缺點是:由於程式中是以陣列來對應需要顯示的值,一旦我們在程式中使用了超過陣列索引的值,程式的執行就會產生問題。 • 為了解決這些問題,J2SE 5.0提供了新的列舉資料的設計機制
14-2 使用enum關鍵字設計列舉資料 • 為了避免設計列舉資料必需使用陣列來對應資料的缺點,在J2SE 5.0中提供了一個新的關鍵字「enum」可被用來設計列舉資料。 • 定義enum資料的語法為: [存取修飾子] enum 列舉名稱 {值1, 值2, ..., 值n} • 定義enum的存取修飾子可以是private、(default)、public。 • 在「中括號 ({ })」中的列舉值是以「逗號 ( , ) 」作為區隔。 • 列舉值的宣告必需是符合Java變數命名方式的文字,並不是指literal常數。 • 設定列舉值時不可以加上存取修飾字,但是,列舉值自動具有public、final、static等特性。 • 列舉值是不可以再更改的。 • 當您定義了列舉資料後,您也就是定義了一個新的資料型態。
14-2 使用enum關鍵字設計列舉資料 • 列舉資料的定義範例: class EnumData{ public enum Season { SPRING, SUMMER, AUTUMN, WINTER } } • 新的語法不需要再自行定義陣列來對照列舉值了。 • 而且,整個列舉資料的架構也更明顯,因為我們可以很清楚的分辨出SPRING、SUMMER、AUTUMN、和WINTER等列舉值都是屬於Season這個資料型別的常數值。
14-2 使用enum關鍵字設計列舉資料 • 在使用上,如果要在別的類別中使用列舉值,我們要使用以下的語法: 類別名稱.列舉名稱.列舉值; • 如果要在同一個類別中使用列舉值,我們要使用以下的語法: 列舉名稱.列舉值; Season s = Season.SPRING;
14-2-1 使用switch來判斷列舉值 • 在J2SE 5.0中,switch除了可以判斷int、short、byte等型別的值之外,switch還可以判斷列舉資料型態。 • 範例如同: Season s = Season.SPRING; switch (s){ case SPRING:System.out.println("選擇了:" +s);break; case SUMMER:System.out.println("選擇了:" +s);break; case AUTUMN:System.out.println("選擇了:" +s);break; case WINTER:System.out.println("選擇了:" +s); } • 雖然列舉資料可以使用於switch之中,但這不表示列舉值的型別可以轉換成int的型態。因此,以下的轉型方式都會產生編譯錯誤: Season s = Season.SPRING; int a = s; //會產生inconvertible types的編譯錯誤 int b = (int)s; //會產生inconvertibletypes的編譯錯誤
14-2-2 使用foreach來顯示列舉值 • 如果程式中需要顯示所有的列舉值,我們可以使用「values」方法來傳回列舉值。傳回的列舉值是以陣列的型式儲存的。請參考以下的範例: Season[] season = Season.values(); for (Season s: season) System.out.print(s + " "); • 或是: for (int i=0; i < season.length; i++) System.out.print(season[i] + " ");
14-2-3 在類別中使用列舉資料 public static void main(String[] args) { Vacation v = new Vacation(); v.setSpring(Season.SPRING); //使用列舉資料 System.out.println("季節是:" + v.getSpring()); } } //定義列舉資料 enum Season { SPRING, SUMMER, AUTUMN, WINTER }
14-3 使用Enum類別 • 在J2SE 5.0中,列舉資料是以類別的方式來處理的。 • Enum類別定義於「java.lang」套件之下,如同所有的類別都是繼承自Object類別一樣,我們在程式中使用enum關鍵字定義的所有列舉型別都是繼承自Enum類別。 • 我們在程式中宣告的enum也會產生類別檔。 • 例如:宣告 class Test { enum myenum { /* some code here */} } • 程式在編譯完成後,會產生Test.class和Test$myenum.class兩個類別檔。 • 例如:宣告 class Test{ /* some code here */ } enum myenum{ /* some code here */ } • 則是會在程式編譯後,產生Test.class和myenum.class兩個類別檔。
14-3 使用Enum類別 • Enum類別實作了Serializable介面,該介面使得Enum類別具有序列化的能力。 • Enum類別也實作了Comparable介面,該介面使得Enum類別中的值具有順序性。 • Enum類別的建構子只有一個,格式如下: • Enum類別的建構子是protected型態,我們不可以啟動該建構子,也就是說,程式中不可以使用new來建構出一個Enum物件。建構子中的name參數是列舉值的名稱,而ordinal則是列舉值的宣告次序,第一個宣告的列舉值的次序為0。
14-3 使用Enum類別 • Enum類別提供的方法有:
14-3-1 覆寫toString方法 • 使用toString方法所取得的列舉值的名稱其實是和使用name方法取得的名稱是相同的。但我們也有可能覆寫這個方法,以便取得更符合實際需求的列舉值名稱。 • 當您需要覆寫Enum類別的方法,或是自訂新方法時,您必需建立您的enum的建構子。 • 建構子中可以依照您的需求設定參數的類型或是個數,但建構子的存取修飾字只能使用(default)或是private,程式中不可以使用public來當作是enum建構子的修飾字。 • 這是因為Enum類別是不能使用new來產生物件的,因此,我們的程式中不能使用new來實體化自定的enum。
14-4 使用EnumMap類別 • 為了依據特定的狀況來顯示不同的訊息,在J2SE 5.0中,新的EnumMap類別提供了新的解決方案。 • 產生EnumMap物件的方式有以下幾種: EnumMap em = new EnumMap(class_name); EnumMap em = new EnumMap(enummap_name); EnumMap em = new EnumMap(map_name); • 我們可以用類別、另一個EnumMap或是Map物件來產生EnumMap物件。 • EnumMap類別實作了Map介面,因此,我們可以用操作Map的方式來使用EnumMap類別。 • Map物件需要有key和value,在EnumMap類別中,我們可以使用列舉值當作是key,而將需要顯示的訊息當做是value,這樣就可以很容易的產生對映的關係了。 • 在EnumMap內部中,這種對應關係是使用陣列來處理的。
14-4 使用EnumMap類別 • 在EnumMap物件中是不允許有null的key值,這點和一般的Map的使用有些不同。 • 如果您在EnumMap中使用了null的key值,程式會丟出NullPointerException例外物件 • EnumMap物件使用於多執行緒的環境下也會產生問題。如果您在多執行緒的環境下使用EnumMap,並允許執行緒修改物件的內容,那您必需要自行處理同步的問題。最好的方式是在建構EnumMap物件時,即設定同步執行的機制。使用的方式如下: Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap(...));
14-5 使用EnumSet類別 • 當我們需要將多個列舉值組合成一個新物件時,使用J2SE 5.0中提供的新的EnumSet類別會是一種很好的選擇。 • EnumSet類別可以用來組合多個列舉值,而建構EnumSet物件的方法只要使用該類別提供的of方法就可以利用多個列舉值來組成一個EnumSet物件 • 使用範例如同: class DeclareEnumSet1 { enum Week {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY} public static void main(String[] args) { //建構EnumSet物件 EnumSet<Week> es = EnumSet.of(Week.SUNDAY, Week.SATURDAY); } }
14-5 使用EnumSet類別 • 除了of方法之外,EnumSet還提供了其他的方法: