Java 枚舉類

手動實現枚舉類

手動實現枚舉類

實例有限並且固定的類,在Java裏被稱爲枚舉類。java

早期採用經過定義類的方式來實現,能夠採用以下設計方式程序員

  • 經過private將構造器隱藏起來this

  • 把這個類的全部可能實例都使用public static final 修飾的類變量來保存設計

  • 若是與必要,能夠提供一些靜態方法,容許其餘程序根據特定參數來獲取與之匹配的實例code

  • 使用枚舉類可使程序更加健壯,避免建立對象的隨意性對象

Java從JDK1.5後就增長了對枚舉類的支持。繼承

枚舉類入門

Java5新增了一個enum關鍵字(它與class、interface關鍵字的地位相同),用以定義枚舉類。枚舉類是一種特殊的類,它同樣能夠有本身的成員變量、方法,能夠實現一個或多個接口,也能夠定義本身的構造器。一個Java源文件中最多隻能定義一個public訪問權限的枚舉類,且該Java源文件也必須和該枚舉類的類名相同。索引

  • 枚舉類能夠實現一個或多個接口,使用enum定義的枚舉類默認繼承了java.lang.Enum類,而不是默認繼承Object類,所以枚舉類不能顯示繼承其餘父類。其中java.lang.Enum類實現了java.lang.Serializable和java.lang.Comparable兩個接口。接口

  • 使用enum定義、非抽象的枚舉類默認會使用final修飾,所以枚舉類不能派生子類。get

  • 枚舉類的構造器只能使用private訪問控制符,若是省略了構造器的訪問控制符,則默認使用private修飾;若是強制指定訪問控制符,則只能指定private修飾符。

  • 枚舉類的全部實例必須在枚舉類的第一行顯式列出,不然這個枚舉類永遠都不能產生實例。列出這些實例時,系統會自動添加public static final 修飾,無須程序員顯式添加。

枚舉類默認提供了一個values()方法,該方法能夠很方便地遍歷全部的枚舉值。

public enum SeasonEnum
{
    //在第一行列出4個枚舉實例
    SPRING,SUMMER,FALL,WINTER;
}

編譯上面Java程序,將生成一個SeasonEnum.class文件,這代表枚舉類是一個特殊的Java類。
全部的枚舉值之間以英文逗號(,)隔開,枚舉值列舉結束後以英文分號做爲結束。這些枚舉值表明了該枚舉類的全部可能的實例。

public class EnumTest 
{
    public void judge(SeasonEnum s)
    {
        //switch語句裏的表達式能夠是枚舉值
        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) 
    {
        //枚舉類默認有一個values()方法,返回該枚舉類的全部實例
        for(SeasonEnum s : SeasonEnum.values())
        {
            System.out.println(s);
        }
        //使用枚舉實例時,可經過EnumClass.variable形式來訪問
        new EnumTest().judge(SeasonEnum.SPRING);
    }
}

當switch控制表達式使用枚舉類型時,後面case表達式中的值直接使用枚舉值的名字,無須添加枚舉類做爲限定。
java.lang.Enum類中提供了以下幾個方法:

  • int compareTo(E o):該方法用於與指定枚舉對象比較順序,同一個枚舉實例只能與相同類型的枚舉實例進行比較。若是該枚舉對象位於指定枚舉對象以後,則返回正整數;若是該枚舉對象位於指定枚舉對象以前,則返回負整數,不然返回零。

  • String name():返回此枚舉實例的名稱,這個名稱就是定義枚舉類時列出的全部枚舉值之一。與此方法相比,大多數程序員應該優先考慮使用toString()方法,由於toString()方法返回更加用戶友好的名稱。

  • int ordinal():返回枚舉值在枚舉類中的索引值(就是枚舉值在枚舉聲明中的位置,第一個枚舉值的索引值爲零)。

  • String toString():返回枚舉常量的名稱,與name方法類似,但toString()方法更經常使用。

  • public static <T extends Enum <T>> T valueOf(Class<T>enumType, String name):這是一個靜態方法,用於返回指定枚舉類中指定名稱的枚舉值。名稱必須與在該枚舉類中聲明枚舉值時所用的標識符徹底匹配,不容許使用額外的空白字符。

當程序使用System.out.println(s)語句來打印枚舉值時,實際上輸出的是該枚舉值的toString()方法,也就是輸出該枚舉值的名字。

枚舉類的成員變量、方法和構造器

枚舉類的實例只能是枚舉值,而不是隨意地經過new來建立枚舉類對象。

public enum Gender 
{
    MALE,FEMALE;
    //定義一個public修飾的實例變量
    private 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();
    }
}
public class GenderTest 
{
    public static void main(String[] args) 
    {
        //經過Enum的valueOf()方法來獲取指定枚舉類的枚舉值
        //Gender gender = Enum.valueOf(Gender.class, "FEMALE");
        Gender g = Gender.valueOf("FEMALE");
        g.setName("女");
        System.out.println(g+"表明:"+g.getName());
        g.setName("男");
        System.out.println(g+"表明:"+g.getName());
    }
}

枚舉類一般應該設計成不可變類,成員變量值不容許改變,將枚舉類的成員變量都使用private final修飾。若是將全部的成員變量都使用final修飾符來修飾,必須在構造器裏爲這些成員變量指定初始值,爲枚舉類顯式定義帶參數的構造器。

一旦爲枚舉類顯式定義了帶參數的構造器,列出枚舉值時就必須對應地傳入參數。

public enum Gender 
{
    //此處的枚舉值必須調用對應的構造器來建立
    MALE("男"),FEMAL("女");
    private final String name;
    private Gender(String name)
    {
        this.name =name;
    }
    public String getName()
    {
        return this.name();
    }
}

實現接口的枚舉類

枚舉類也能夠實現一個或多個接口。與普通類實現一個或多個接口徹底同樣,枚舉類實現一個或多個接口時,也須要實現該接口所包含的方法。

public interface GenderDesc
{
    void info();
}

若是由枚舉類來實現接口裏的方法,則每一個枚舉值在調用該方法時都有相同的行爲方式(由於方法體徹底同樣)。若是須要每一個枚舉值在調用該方法時呈現出不一樣的行爲方式,則可讓每一個枚舉值分別來實現該方法,每一個枚舉值提供不一樣的實現方式,從而讓不一樣的枚舉值調用該方法時具備不一樣的行爲方式。

public enum Gender implements GenderDesc
{
    // 此處的枚舉值必須調用對應構造器來建立
    MALE("男")
    // 花括號部分其實是一個類體部分
    {
        public void info()
        {
            System.out.println("這個枚舉值表明男性");
        }
    },
    FEMALE("女")
    {
        public void info()
        {
            System.out.println("這個枚舉值表明女性");
        }
    };
    // 其餘部分與codes\06\6.9\best\Gender.java中的Gender類徹底相同
    private final String name;
    // 枚舉類的構造器只能使用private修飾
    private Gender(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }
    // 增長下面的info()方法,實現GenderDesc接口必須實現的方法
    public void info()
    {
        System.out.println(
            "這是一個用於用於定義性別的枚舉類");
    }
}

當建立MALE和FEMALE兩個枚舉值時,後面又緊跟了一對花括號,這對花括號裏包含了一個info()方法定義。花括號部分實際上就是一個類體部分,在這種狀況下,當建立MALE和FEMALE枚舉值時,並非直接建立Gender枚舉類的實例,而是至關於建立Gender的匿名子類的實例。

並非全部的枚舉類都使用了final修飾。非抽象的枚舉類才默認使用final修飾。對於一個抽象的枚舉類而言——只要它包含了抽象方法,它就是抽象枚舉類,系統會默認使用abstract修飾,而不是使用final修飾。

編譯上面的程序,生成了Gender.class、Gender$1.class和Gender$2.class三個文件,證實了:MALE和FEMALE其實是Gender匿名子類的實例,而不是Gender類的實例。當調用MALE和FEMALE兩個枚舉值的方法時,就會看到兩個枚舉值的方法表現不一樣的行爲方式。

包含抽象方法的枚舉類

public enum Operation 
{
    PLUS
    {
        public double eval(double x, double y) 
        {
            return x + y;
        }
    },
    MINUS
    {
        public double eval(double x, double y) 
        {
            return x - y;
        }
    },
    TIMES
    {
        public double eval(double x, double y) 
        {
            return x * y;
        }
    },
    DIVIDE
    {
        public double eval(double x, double y) 
        {
            return x / y;
        }
    };
    //爲枚舉類定義一個抽象方法
    //這個抽象方法由不一樣的枚舉值提供不一樣的實現
    public abstract double eval(double x, double y);
    public static void main(String[] args) 
    {
        System.out.println(Operation.PLUS.eval(3, 4));
        System.out.println(Operation.MINUS.eval(5, 4));
        System.out.println(Operation.TIMES.eval(8, 8));
        System.out.println(Operation.DIVIDE.eval(1, 5));
    }
}

枚舉類裏定義抽象方法時不能使用abstract關鍵字將枚舉類定義成抽象類(由於系統自動會爲它添加abstract關鍵字),但由於枚舉類須要顯式建立枚舉值,而不是做爲父類,因此定義每一個枚舉值時必須爲抽象方法提供實現,不然將出現編譯錯誤。

相關文章
相關標籤/搜索