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其他類一樣,可以實現一個或多個接口。