1.一個類的實例是有限且固定的,這個類稱為枚舉類。比如季節類,只有四個對象(春、夏、秋、冬)
2.手動實現一個枚舉類
(1)通過private將構造器隱藏起來
(2)把這個類的所有可能實例都使用private static final修飾的類變量來保存。
(3)如果有必要,可以提供一些靜態方法。
package cn.it.lsl; public class Season { private final String name; private final String desc; private Season(String name, String desc){ this.name = name; this.desc = desc; } public static final Season SPRING = new Season("春天","踏青"); public static final Season SUMMER = new Season("夏天","夏日炎炎"); public static final Season FAIL = new Season("秋天","秋高氣爽"); public static final Season WINTER = new Season("冬天","白雪皚皚"); public String getName(){ return this.name; } public String getDesc(){ return this.desc; } }
package cn.it.lsl; public class SeasonTest { public SeasonTest(Season s){ System.out.println(s.getName() + "," + s.getDesc()); } public static void main(String[] args) { new SeasonTest(Season.FAIL); } }
Season類是一個不可變類。Season類中包含了4個static final常量的Field,這4個常量Field就代表了該類所能創建的對象。當程序需要調用Season對象時,就可以通過Season.SPRING的方式來取得Season對象。
這里順便復習一下不可變類
不可變類:創建該類的實例后,該實例的Field是不可改變的。
如果要創建自定義的不可變類,需遵循如下規則:
(1)使用private和final修飾符來修飾該類的Field。
(2)提供帶參數的構造函數,用於根據傳入參數來初始化類里的Field。
(3)僅為該類的Field提供getter方法,不要為該類的Field提供setter方法。
(4)如果有必要,重寫Object類的hashCode和equals方法。
3.枚舉類
(1)使用enum關鍵字定義枚舉類。枚舉類一樣可以有自己的Field、方法,可以實現一個或多個接口,也可以有自己的構造器。
(2)使用eunm定義的枚舉類默認繼承了java.lang.Enum類,而不是繼承Object類。
(3)使用enum定義、非抽象的枚舉類默認會使用final修飾,因此枚舉類不能派送子類。(並不是所有的枚舉類都使用final修飾,如抽象枚舉類)
(4)枚舉類所有實例必須在枚舉類的第一行顯示列出,否則這個枚舉類永遠不能產生實例。
(5)所有枚舉類都提供一個values方法,該方法可以方便地遍歷所有枚舉值。
package cn.lsl; public enum SeasonEnum { SPRING,SUMMER,FALL,WINTER; }
package cn.lsl; public class EnumTest { public void judge(SeasonEnum s){ switch(s){ case SPRING: System.out.println("春天"); break; case SUMMER: System.out.println("夏天"); break; case FALL: System.out.println("秋天"); break; case WINTER: System.out.println("冬天"); break; } } public static void main(String[] args) { //列出所有枚舉類的實例 for(SeasonEnum s : SeasonEnum.values()){ System.out.println(s); } new EnumTest().judge(SeasonEnum.FALL); } }
4.枚舉類的Field、方法
枚舉類可以定義自己的Field和方法。
package cn.lsl; public enum Gender { MALE,FEMALE; public String name; }
package cn.lsl; public class GenderTest { public static void main(String[] args) { //通過Enum的valueOf方法來獲取指定枚舉類的枚舉值 Gender g = Enum.valueOf(Gender.class, "FEMALE"); g.name = "女"; System.out.println(g + "," + g.name); } }
在上面程序中產生Gender對象的方式與普通類不同,而是采用通過Enum的valueOf方法來獲取指定枚舉類的枚舉值,枚舉類的實例只能是枚舉值,而不是隨意通過new來創建的。
其實上面程序中,沒有實現java的良好封裝,因為name的訪問權限是public,這樣就會出現隨意對name賦值的情況,應該通過方法來控制對name的訪問。
改造上面的程序
package cn.lsl; public enum Gender { MALE,FEMALE; public String name; public void setName(String name){ switch(this){ case MALE: if(name.equals("男")){ this.name = name; }else{ System.out.println("參數錯誤"); return; } break; case FEMALE: if(name.equals("女")){ this.name = name; }else{ System.out.println("參數錯誤"); return; } break; } } public String getName(){ return this.name; } }
package cn.lsl; public class GenderTest { public static void main(String[] args) { //通過Enum的valueOf方法來獲取指定枚舉類的枚舉值 Gender g = Enum.valueOf(Gender.class, "FEMALE"); g.setName("女"); System.out.println(g + "," + g.getName()); g.setName("男"); System.out.println(g + "," + g.getName()); } }
定義枚舉類,以上的做法還是做的不夠好,枚舉類通常應該設計不可變類。其Field值不應該允許改變,這樣會更安全。
所以枚舉類的Field都應該使用private final修飾。
package cn.lsl; public enum Gender { MALE("男"),FEMALE("女"); private final String name; private Gender(String name){ this.name = name; } public String getName(){ return this.name; } }
5.實現接口的枚舉類
枚舉類可以實現一個或多個接口。
package cn.it.lsl; public interface GenderDesc { void info(); }
package cn.it.lsl; public enum Gender implements GenderDesc{ MALE("男"),FEMALE("女"); private final String name; private Gender(String name){ this.name = name; } public String getName(){ return this.name; } @Override public void info() { // TODO Auto-generated method stub System.out.println("枚舉類實現接口"); } }
以上在枚舉類里面實現接口的方法時,每個枚舉值在調用該方法的時候都會有相同的行為(即方法體相同)。
如果需要每個枚舉值在調用該方法時表現出不同的行為方式,應該讓每個枚舉值分別實現該方法。
package cn.it.lsl; public enum Gender implements GenderDesc{ MALE("男"){ public void info() { // TODO Auto-generated method stub System.out.println("枚舉類實現接口,男"); } }, FEMALE("女"){ public void info() { // TODO Auto-generated method stub System.out.println("枚舉類實現接口,女"); } }; private final String name; private Gender(String name){ this.name = name; } public String getName(){ return this.name; } }
6.包含抽象方法的枚舉類
在枚舉類中定義抽象方法的時候不能使用abstract關鍵字將枚舉類定義成抽象類(因為系統會自動為它添加abstract關鍵字),因為枚舉類需要顯示創建枚舉值,而不是作為父類,所以定義每個枚舉值時必須為抽象方法提供實現。
以下一個程序在枚舉類中定義了一個抽象方法,這個抽象方法由不同的枚舉值提供不同的實現
package cn.it.lsl; public enum Operation { PLUS{ @Override public double eval(double x, double y) { // TODO Auto-generated method stub return x + y; } }, MINUS{ @Override public double eval(double x, double y) { // TODO Auto-generated method stub return x - y; } }, TIMES{ @Override public double eval(double x, double y) { // TODO Auto-generated method stub return x * y; } }, DIVIDE{ @Override public double eval(double x, double y) { // TODO Auto-generated method stub return x / y; } }; public abstract double eval(double x, double y); public static void main(String[] args) { System.out.println(Operation.PLUS.eval(2, 3)); System.out.println(Operation.MINUS.eval(2, 3)); System.out.println(Operation.TIMES.eval(2, 3)); System.out.println(Operation.DIVIDE.eval(2, 3)); } }