枚舉

Java 1.5發行版中增加了兩個新的引用類型家族:一種新的類稱作枚舉類型(enum type),一種新的接口稱作註解類型(annotation type)。


>枚舉

枚舉類型是指由一組固定的常量組成合法值的類型。

  • Java枚舉本質上是int值,Java枚舉類型背後的基本思想是:它們是通過公有的靜態final域爲每個枚舉常量導出實例的類;
  • 由於沒有可訪問的構造器,枚舉類型是真正的final。客戶端既不能創建枚舉類型的實例,也不能對它進行擴展,所以很可能沒有實例,而只有聲明過的枚舉常量。它們是實例受控的,是單例(Singleton)的泛型化,本質上是單元素的枚舉;
  • Java中,枚舉定義了一種類類型,將枚舉定義爲類,極大地擴展了枚舉的概念。在Java中,枚舉可以具有構造函數、方法、以及實例變量。

>創建和使用枚舉

定義一個簡單的enum

enum Apple{
FUJI,PIPPIN,CRANNY_SMITH
}


創建枚舉用enum關鍵字,標識符FUJI、PIPPIN等被稱爲枚舉常量,每個枚舉常量被隱式聲明爲Apple的公有、靜態、final成員。枚舉常量的類型是聲明它們的枚舉的類型,如上例代碼中是Apple。在Java語言中,這些常量被稱爲”自類型化的”(sefl-type),其中的”自”指封裝常量的枚舉。對以上代碼編譯後會看到編譯器將enum類型單獨編譯成字節碼文件Apple.class,使用javap查看

這裏寫圖片描述

定義了枚舉後,可以創建枚舉類型的變量,然而,雖然枚舉定義了類類型,卻不用new實例化枚舉,枚舉變量的使用方式很大程度上與基本類型相同。獲取Apple枚舉類的一個實例:

Apple a = Apple.FUJI;

>構造器

枚舉類是class,在枚舉類型中有構造器、方法、數據域。枚舉類的構造器是在構造枚舉常量的時候被調用。 每個枚舉常量都是所屬枚舉類型的對象。如果爲枚舉定義了構造函數,當創建每個枚舉常量是都會調用該構造函數。對於枚舉定義的實例變量,每個枚舉常量都有它自己的副本。
代碼示例

package com.afy.enumdemo;

enum Apple{
    Jonathan(10), GoldenDel(9),RedDel(12),Winesap(15),Cortland(8);

    private int price;     //price of each apple

    //Constructor
    private Apple(int p) {
        price = p;
    }

    int getPrice(){
        return price;
    }
}

class AppleEnumDemo {

    public static void main(String[] args) {
        Apple ap;

        //Display price of Winesap.
        System.out.println("Winesap costs" + Apple.Winesap.getPrice() + "cents.\n");

        //Display all apples and prices.
        System.out.println("All apple price:");
        for(Apple a : Apple.values())
            System.out.println(a + "cost" + a.getPrice() + "cents.");
    }

}

這段代碼中有實例變量price,有Apple構造函數,有getprice()方法。每個常量後面圓括號中的數值是指定構造函數參數,這些數值被傳遞給Apple()方法的參數p,然後將這些值賦給price變量.當在main()方法中聲明變量ap時,對於每個特定的常量調用Apple的構造函數一次

每個枚舉變量都由自己的price變量副本,可以調用getPrice()方法來獲取指定類型蘋果的價格,若獲取Cortland的價格:

Apple.Cortland.getPrice()

也可以通過for循環獲取所有品種的蘋果價格。由於每個枚舉常量都有price變量的副本,所以與枚舉常量關聯的值是獨立的,並且和與其他常量關聯的值不同。將枚舉作爲類實現像Java一樣,纔有這樣強大的功能。

針對構造器,就像其他類一樣,枚舉提供多種重載形式。可以將price變量初始化爲-1.表明不能獲得價格數據:

//Use an enum constructor.
enum Apple{
  Jonathan(10),GoldenDel(9),RedDel,Winesap(15),Cortland(8);

  private int price;  //price of each apple

  //Constructor
  Apple(int p){
     price = p;
  }

  //Overloaded constructor
  Apple(){
    price = -1;
 }

 int getPrice(){
 return price;
 }
}

這裏沒有給RedDel賦參數,這樣會調用默認構造函數,並將RedDel的price變量設置爲-1。

構造器只能使用私有private訪問控制符,而不應有public構造器,以保證外部代碼無法新構造枚舉類的實例,我們已知道枚舉常量是public static final的常量,即枚舉對象的屬性不應允許改動。然而枚舉類的方法和數據域允許外部訪問。

枚舉switch的語句用法

枚舉值可以用於控制switch語句,可以在switch表達式中使用Enum定義的枚舉類的對象作爲表達式,case子句可以直接使用枚舉值的名字,枚舉常量的名稱沒有使用枚舉類型的名稱進行限定,如直接用Jonathan,而不用Apple.Jonathan,因爲switch表達式中的枚舉類型已經隱式指定了case常量的枚舉類型,故不使用枚舉類型的名稱對常量進行限定,而如果這樣試圖這麼做的話,會造成編譯時錯誤。如

System.out.println(Apple.Jonathan);

這樣做打出“Jonathan”。

示例代碼

package com.afy.enumdemo;

enum Apple1 {
    Jonathan,GoldenDel,RedDel,Winesap,Cortland
}

class EnumSwitchDemo {
    public static void main(String[] args) {
        Apple1 ap ;

        ap = Apple1.RedDel;

        //OUtput an enum value.
        System.out.println("value of ap is: " + ap);
        System.out.println();

        ap = Apple1.GoldenDel;

        //compare two enum values
        if (ap==Apple1.GoldenDel) {
            System.out.println("ap contains GoldenDel.\n");         
        }

        //Use an enum to control a switch statement,
        switch (ap) {
        case Jonathan:
            System.out.println("Jonathan is red");
            break;

        case GoldenDel:
            System.out.println("Golden delicios is yellow");
            break;

        case RedDel:
            System.out.println("Red Delicious is red");
            break;
        case Winesap:
            System.out.println("Winesap is red");
            break;
        case Cortland:
            System.out.println("Cortland is red");
            break;
        }
    }
}


values()和valueOf()方法

所有枚舉都自動包含兩個預定義方法:values()和valueOf()。它們的一般形式如下:
public static enum-type [] values()
public static enum-type [] valueOf(String str)


values()方法返回一個包含枚舉常量列表的數組,valueOf()方法返回與傳遞到參數str的字符串相對應的枚舉常量。enum-type是枚舉類型,如Apple枚舉,Apple.vallueOf(“Winesap”)返回的是Winesap。

代碼示例

package com.afy.enumdemo;

enum Apple2{
    Jonathan,GoldenDel,RedDel,Winesap,Cortland
}

public class ValuesAndValueOfDeme {
    public static void main(String[] args) {
        Apple ap;

        System.out.println("Here are all Apple constants:");

        //use values()
        Apple allapples[] = Apple.values();
        for (Apple a : allapples) {
            System.out.println(a);
        }

        System.out.println();

        //use valueOf()
        ap = Apple.valueOf("Winesap");
        System.out.println("ap contains " + ap);
    }
}


這裏使用for-each風格的for循環來遍歷values()方法返回的常量數組。爲了進行說明,創建變量allapples,並將其賦值爲對枚舉數組的引用,但不一定要這樣,可以如下:

for(Apple a : Apple.values())
  System.out.println(a);


枚舉的限制

1. 枚舉不能繼承其他類;
2. 枚舉不能是超類,這意味着枚舉不能擴展;

除此之外,枚舉與其他類相似,尤其要注意的是:每個枚舉常量都是定義它的類的對象。

>枚舉都繼承Enum類

儘管聲明枚舉時不能繼承超類,但是

這裏寫圖片描述

java.lang.Enum這個類定義了所有枚舉都可以使用的一些方法。

這裏寫圖片描述

>枚舉實現接口

枚舉和Java其他類一樣,可以實現一個或多個接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章