很多同學(xué)在學(xué)習(xí)Java的過程中可能會聽到一種叫枚舉的數(shù)據(jù)類型,那到底什么是枚舉呢?
在Java程序中又是怎么使用枚舉的呢?
下面我們就簡單的講解下這個(gè)神秘的枚舉類型。
什么是枚舉?
枚舉:枚舉其實(shí)就是一種數(shù)據(jù)類型,跟int, char 這種差不多。是JDK1.5以后引入的一種新的數(shù)據(jù)類型。
它有一定的特點(diǎn)就是:在創(chuàng)建好一個(gè)枚舉類型后,能夠使用的量,只能是enum里面規(guī)定的值。
當(dāng)然在定義枚舉時(shí),有要求:枚舉中的量必須是不變的,并且是有限的。
什么意思呢?
例如:
一周中的周一(MONDAY), 周二(TUESDAY), 周三(WEDNESDAY), 周四(THURSDAY), 周五(FRIDAY), 周六(SATURDAY), 周末(SUNDAY)。
對于我們來說,一周中的時(shí)間,從周一到周末是不會改變的,并且是有限的,就可以使用枚舉來展示一周中的數(shù)據(jù)。
當(dāng)然除了一周的時(shí)間的滿足條件以外,在生活中還有很多枚舉的存在,如:“春夏秋冬”四季、“上下左右”方向,也可以使用枚舉來表示。
那我們在Java程序中如何書寫枚舉呢?
當(dāng)然同學(xué)們都是有一定Java基礎(chǔ)的,那如果我們想要把一周的時(shí)間表示出來,在JDK1.5之前,那時(shí)沒有枚舉的話,該怎么做呢?
通過初步分析,我們發(fā)現(xiàn)一周中的時(shí)間都是不變的,那我們應(yīng)該使用常量來表示
代碼如下:
public class Week{
public static final String MON = "MONDAY";
public static final String TUE = "TUESDAY";
public static final String WED = "WEDNESDAY";
public static final String THU = "THURSDAY";
public static final String FRI = "FRIDAY";
public static final String SAT = "SATURDAY";
public static final String SUN = "SUNDAY";
}
這樣定義后,在Java代碼中可以直接使用Week.MON的方式來調(diào)用Week類中的值。
當(dāng)然,我們還可以偷個(gè)懶,將上述代碼寫在接口中(因?yàn)榻涌诙x的變量默認(rèn)都是public static final)
最終變成:
public interface IWeekConstants {
String MON = "Mon";
String TUE = "Tue";
String WED = "Wed";
String THU = "Thu";
String FRI = "Fri";
String SAT = "Sat";
String SUN = "Sun";
}
這樣確實(shí)要簡單一點(diǎn)了,那我們用枚舉還能更簡單嗎?
OK,我們用枚舉試試:
public enum WeekEnum {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
這真不是一般的簡單。
在我們使用枚舉時(shí)只需要把確定的值一個(gè)一個(gè)的列舉出來即可,因?yàn)樵谑褂妹杜e來表示這些數(shù)據(jù)時(shí)它們就已經(jīng)確定了值,并不需要擔(dān)心量的變化。
所以,在某種情況下,使用枚舉也是一種不錯(cuò)的選擇。
當(dāng)然,在定義枚舉的過程有有一些要求:
1.首先創(chuàng)建枚舉類型要使用 enum 關(guān)鍵字–public enum WeekEnum{},類似于類的創(chuàng)建過程。
2.每個(gè)枚舉量之間用“,”隔開,就像:MON, TUE, WED, THU, FRI, SAT, SUN
當(dāng)然,最后的SUN后面可以不加“;”,但為了代碼整體的展示,加上“;”更能體現(xiàn)書寫代碼時(shí)的好習(xí)慣。
OK,到這里,肯定會有人會問:“枚舉怎么寫得那么簡單啊!”
其實(shí)枚舉僅僅只是看起來寫得很簡單。
枚舉書寫簡單的原因是:在枚舉中,每一個(gè)枚舉對象在創(chuàng)建時(shí)都會默認(rèn)繼承java.lang.Enum這個(gè)類。
但由于java.lang.Enum這個(gè)類是抽象類,所以不能直接創(chuàng)建其對象。
所以每寫一個(gè)枚舉對象,實(shí)際上就創(chuàng)建一個(gè)Enum的子類(Enum本身是一個(gè)抽象類),而在每次創(chuàng)建枚舉的子類時(shí)都會自動映射到下述的構(gòu)造器中創(chuàng)建對象:
protected Enum(String name, int ordinal)
在該構(gòu)造器中,每個(gè)枚舉的名稱都被轉(zhuǎn)換成一個(gè)字符串,并且序數(shù)設(shè)置表示了此設(shè)置被創(chuàng)建的順序。
例如上述的枚舉代碼中,一共是周一到周末,創(chuàng)建了7個(gè)枚舉對象,相當(dāng)于調(diào)用了7次
protected Enum(String name, int ordinal)
在這個(gè)構(gòu)造函數(shù)中,name 是常量,如:上面所寫的MON,TUE等;ordinal是被創(chuàng)建序數(shù)(從0開始)。
效果相當(dāng)于:
public enum WeekEnum {
new Enum<EnumTest>("MON",0);
new Enum<EnumTest>("TUE",1);
new Enum<EnumTest>("WED",2);
...
}
所以說,枚舉看起來很簡單,但是在執(zhí)行時(shí)依然做了很多準(zhǔn)備工作。
那在Java代碼中怎么運(yùn)用呢?
用法一:常量
enum Color{
GREEN, YELLOW, RED
}
上述例子中,GREEN, YELLOW, RED都是常量,這是枚舉中常用的方式之一。
我們首先創(chuàng)建了一個(gè)枚舉類,并且在其中創(chuàng)建3個(gè)枚舉對象
接下來看看如何得到枚舉中的子類對象
public class TrafficLight {
//使用枚舉對象和使用靜態(tài)屬性差不多
//首先通過枚舉名,再加上.運(yùn)算符找到對應(yīng)的常量名,返回的是一個(gè)枚舉對象
Color color = Color.RED;
//那么color就是一個(gè)枚舉對象,并對應(yīng)RED
}
通過上述例子,相信同學(xué)們都大致了解如何獲得枚舉對象了。
上面我們也說了枚舉和int、char一樣都是數(shù)據(jù)類型,那能不能在switch中使用呢?
用法二:switch
接下來看看在switch中如何使用枚舉
接著上面的代碼:
public void change() {
switch (color) {//將枚舉對象放入switch參數(shù)列表中
case RED:
System.out.println("紅色");
break;
case YELLOW:
System.out.println("黃色");
break;
case GREEN:
System.out.println("綠色");
break;
}
}
將枚舉對象放入switch參數(shù)列表中是JDK1.5以后的新方式,可以把枚舉對象看做參數(shù)來使用,其對應(yīng)的就是它所代表的的值。
如上述代碼中,Color color = Color.RED;先取出枚舉對象,然后賦值給color。
這時(shí)color枚舉對象對應(yīng)的就是RED,所以,在case選擇過程中,會被case RED選中,進(jìn)而執(zhí)行case RED中的語句,最終輸出“紅色”。
同理如果在創(chuàng)建枚舉對象時(shí)使用的是Color.YELLOW,則枚舉對象對應(yīng)的就是YELLOW,則會執(zhí)行對象case YELLOW中的語句輸出“黃色”。
注意:在前面也說了,只能使用枚舉中已經(jīng)寫好的對象,所以使用其它沒有的枚舉對象是會出現(xiàn)錯(cuò)誤的。
從上述代碼中相信大家已經(jīng)基本了解了如何在代碼中來使用我們的枚舉對象了,同時(shí),也了解了switch中枚舉的新用法。
下面來個(gè)有難度的。
之前我們說過,枚舉類型在創(chuàng)建時(shí)很類似類的創(chuàng)建,那枚舉能不能和類一樣,在枚舉中創(chuàng)建方法呢?
用法三:向枚舉中添加新方法
如果打算自定義自己的方法,那么必須在enum實(shí)例序列的最后添加一個(gè)分號。而且 Java 要求必須先定義 enum 實(shí)例。
怎么書寫呢?
public enum Color {
//先定義 enum 實(shí)例
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);//;不能忘掉
// 成員變量
private String name;
private int index;
// 構(gòu)造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
從上述代碼中,我們發(fā)現(xiàn)其中不僅創(chuàng)建了枚舉的對象,同時(shí)還出現(xiàn)了構(gòu)造器、成員變量和對應(yīng)的get、set方法,并且還加上了一個(gè)普通的方法。
尤其是RED(“紅色”, 1)這種形式的數(shù)據(jù)。其相當(dāng)于在創(chuàng)建枚舉的RED、GREEN等對象時(shí),使用構(gòu)造器把構(gòu)造出來的對象與枚舉對象進(jìn)行了綁定。
相當(dāng)于枚舉類中的對象只有RED、GREEN、BLANK、YELLO,而這些對象分別擁有對應(yīng)的兩個(gè)成員變量:name和index。
當(dāng)然這種定義方式我們很少見,不過一定得知道哦,不然被問到就尷尬了。
那上述的代碼,我們能不能還像剛才那樣對枚舉對象進(jìn)行使用呢?
通過代碼給大家展示一些常用的方法:
public static void main(String[] args) {
//使用Color.values(),可以返回一個(gè)Color類型的數(shù)組
Color c[] = Color.values();
//既然是個(gè)數(shù)組,進(jìn)行遍歷
for (Color color : c) {
//使用get、set方法中的get方法,得到c對象中對應(yīng)的name值。
System.out.println(color.getName());
//使用get、set方法中的get方法,得到c對象中對應(yīng)的index值。
System.out.println(color.getIndex());
//使用枚舉類的方法ordinal(),得到枚舉對象的索引值(從0開始)
System.out.println(color.ordinal());
//使用枚舉類的方法name(),得到枚舉對象的名稱
System.out.println(color.name());
//直接輸出枚舉對象
System.out.println(color);
}
//根據(jù)枚舉的靜態(tài)方法,通過字符串找到對應(yīng)的枚舉對象
//如果該對象不存在,則出現(xiàn)java.lang.IllegalArgumentException異常
Color c1 = Color.valueOf("RED");
System.out.println(c1);
}
下面對上述方法進(jìn)行了簡單的歸納
簡單介紹在枚舉中常用的一些方法:
1.使用Color.values(),可以返回一個(gè)Color枚舉類型中枚舉對象的數(shù)組。Color[] c = Color.values();
2.也可以通過枚舉類中定義的方法:
首先獲得枚舉類的對象Color c = Color.RED;
通過枚舉類中的方法:c.getName()(這個(gè)是get、set方法),得到c對象中對應(yīng)的”紅色”值。
當(dāng)然也可以通過getIndex()(這個(gè)是get、set方法)得到寫出的數(shù)值。
3.可以使用枚舉類的枚舉對象子代的方法:
同樣首先獲得枚舉類的對象Color c = Color.RED;
(1)c.ordinal();得到該枚舉對象的索引值,當(dāng)然,索引是從0開始。
(2)c.name();得到對應(yīng)的對象名稱如:RED。
(3)System.out.println(c),直接輸出枚舉對象,獲得的同樣是對象名稱:RED。
(4)靜態(tài)方法使用枚舉類來調(diào)用如:Color.valueOf(“RED”),根據(jù)傳入的字符串,找到對應(yīng)的枚舉對象。
通過上述內(nèi)容,相信大家對枚舉也有了一定的了解。
既然在枚舉中我們可以自定義方法,那能不能像類一樣去重寫父類中的方法呢?
用法四:覆蓋枚舉的方法
下面給大家展示一個(gè)比較簡單的重寫例子:
我們在枚舉中重寫toString()方法(所有類的都會隱式的繼承Object類):
public enum Color1 {
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);
// 成員變量
private String name;
private int index;
// 構(gòu)造方法
private Color1(String name, int index) {
this.name = name;
this.index = index;
}
//覆蓋方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
重寫了toString()方法后,發(fā)現(xiàn)在輸出枚舉對象時(shí),其輸出內(nèi)容也發(fā)生了改變,當(dāng)然,在枚舉中也可以加上main方法直接使用
例如:
public enum Color1 {
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);
// 成員變量
private String name;
private int index;
// 構(gòu)造方法
private Color1(String name, int index) {
this.name = name;
this.index = index;
}
//覆蓋方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
public static void main(String[] args) {
Color1 c = Color1.BLANK;
System.out.println(c);
}
}
輸出的結(jié)果也不再是BLANK,而是“3_白色”。
通過上面的講解,我們發(fā)現(xiàn),雖然枚舉在創(chuàng)建過程中和類不同,但是枚舉和類是非常相似的。
下面再給同學(xué)們列舉一些枚舉的其它用法。
用法五:實(shí)現(xiàn)接口
這里簡單的給大家介紹下枚舉如何實(shí)現(xiàn)接口。
直接上代碼:
首先是接口:
public interface Behaviour {
public void print();
public String getInfo();
}
枚舉代碼:
public enum Color implements Behaviour{
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);
// 成員變量
private String name;
private int index;
// 構(gòu)造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
和我們類實(shí)現(xiàn)接口是一樣的,必須要求實(shí)現(xiàn)接口中的方法,并且還有一點(diǎn)特殊點(diǎn)就是枚舉不能只實(shí)現(xiàn)接口的方法,還必要書寫枚舉中的量才可以。
也就是說,必須有RED(“紅色”, 1), GREEN(“綠色”, 2), BLANK(“白色”, 3), YELLO(“黃色”, 4);這些枚舉的量,否則就會報(bào)錯(cuò)誤。
提一個(gè)小問讓同學(xué)們想一想:枚舉可以實(shí)現(xiàn)接口,那枚舉可以繼承類嗎?
這個(gè)答案一定是:不可以!(枚舉默認(rèn)java.lang.Enum這個(gè)類,而Java只能單繼承,所以不可以!)
用法六:使用接口組織枚舉
什么是使用接口組織枚舉呢?
簡單的說就是在接口中創(chuàng)建多個(gè)枚舉變量,其中枚舉同時(shí)實(shí)現(xiàn)該接口
比如說:
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
Food接口的作用就是將其所包含的enum(Coffee、Dessert)組合成一個(gè)公共類型,可以使用Food對其中的枚舉進(jìn)行管理
那這樣我們?nèi)绾问褂妹杜e中的值呢?
可以使用:
1.Coffee coffee = Food.Coffee.BLACK_COFFEE;
2.Coffee coffee = Coffee.BLACK_COFFEE;
3.Food coffee = Coffee.BLACK_COFFEE;
來創(chuàng)建出枚舉的對象,其它的方法沒有區(qū)別,當(dāng)然還可以在接口中添加一些抽象方法
比如:
public interface Food {
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO;
@Override
public void use() {
System.out.println(Coffee.this.getClass());
}
}
enum Dessert implements Food {
FRUIT, CAKE, GELATO;
@Override
public void use() {
System.out.println(Dessert.this.getClass());
}
}
public void use();
}
用法七:關(guān)于枚舉集合的使用
在Java中有java.util.EnumSet和java.util.EnumMap是兩個(gè)枚舉集合。
EnumSet保證集合中的元素不重復(fù)。
EnumMap中的 key是enum類型,而value則可以是任意類型。
簡單的給展示下兩種枚舉集合
EnumSet代碼:
enum Color {
RED, GREEN, BLUE;
}
public class EnumSetDemo {
public static void main(String args[]) {
// 聲明一個(gè)EnumSet對象
EnumSet<Color> esOld = null;
EnumSet<Color> esNew = null;
// 將枚舉的全部類型設(shè)置到EnumSet對象之中
esOld = EnumSet.noneOf(Color.class);
// 增加內(nèi)容
esOld.add(Color.RED);
// 增加內(nèi)容
esOld.add(Color.GREEN);
// 從已有的集合拷貝過來
esNew = EnumSet.copyOf(esOld);
print(esNew);
}
// 專門的輸出操作
public static void print(EnumSet<Color> temp) {
// 循環(huán)輸出EnumSet中的內(nèi)容
for (Color c : temp) {
System.out.print(c + "、");
}
System.out.println();
}
}
EnumMap代碼:
enum Color {
RED, GREEN, BLUE;
}
public class EnumMapDemo {
public static void main(String args[]) {
// 定義Map對象,同時(shí)指定類型
Map<Color, String> desc = null;
// 實(shí)例化EnumMap對象
desc = new EnumMap<Color, String>(Color.class);
// 添加數(shù)據(jù)
desc.put(Color.RED, "紅色");
desc.put(Color.GREEN, "綠色");
desc.put(Color.BLUE, "藍(lán)色");
// 遍歷,并進(jìn)行輸出
for (Color c : Color.values()) {
System.out.println(c.name() + " --> " + desc.get(c));
}
for (Color c : desc.keySet()) {
System.out.print(c.name() + "、");
}
for (String s : desc.values()) {
System.out.print(s + "、");
}
}
}
根據(jù)上述舉的例子,希望同學(xué)們對于枚舉集合的使用有個(gè)直觀的感受。
說了這么多,希望大家對枚舉有更深入的了解,其實(shí)枚舉只是一個(gè)Java和其它很多語言中的一種數(shù)據(jù)類型而已,只是由于其特殊的寫法,在程序中運(yùn)用有所不同。
總結(jié)
這里簡單的總結(jié)一下:
1.由于枚舉的出現(xiàn)時(shí)間比較晚,在我們的項(xiàng)目中使用的頻率是比較低的,但是懂得枚舉的使用可以使你的代碼更為簡潔明了。
2.雖然枚舉的使用看起來很簡單,但它也有自身的局限性(要求枚舉中的數(shù)據(jù)全是不變的,有限的),所以,在編寫程序的過程中應(yīng)該靈活運(yùn)用所學(xué)的只是,這樣才能使自己的程序?qū)懙迷絹碓胶谩?/p>
好的代碼不是一蹴而就的,需要反復(fù)琢磨與思考,懂得合理運(yùn)用才能事半功倍。
浙公網(wǎng)安備 33010602011771號