1. 枚舉概述
枚舉:列舉,一個一個地列出來。
Java枚舉:把某個類型的對象,全部列出來。
- 什么情況下會用到枚舉類型?
某些類的對象只有確定的有限個時,可以把這樣的類聲明為枚舉。
例如:
星期:Monday(星期一)......Sunday(星期天)
性別:Male(男)、Female(女)
月份:January(1月)......December(12月)
季節:Spring(春天)......Winter(冬天)
- 枚舉是一種特殊的類,特殊在它的對象是有限的幾個常量對象。它既是一種類(class)類型卻又比類類型多了些特殊的約束,枚舉的本質是一種受限制的類。
當需要定義一組常量時,可以使用枚舉。
2. 枚舉類型的定義
枚舉是JDK1.5新增的引用數據類型。
-
枚舉的對象的屬性不應允許被改動,所以應該使用 private final 修飾
屬性應該在構造器中為其賦值
若枚舉顯式的定義了帶參數的構造器,則在列出枚舉值時也必須對應地傳入參數
-
枚舉的實現:
- jdk1.5之前,自定義枚舉類
- jdk1.5,可以使用
enum
關鍵字定義枚舉
2.1 自定義枚舉類
- 要求:
- 私有化類的構造器,保證不能在類的外部創建其對象
- 在類的內部創建枚舉類的實例,並用聲明為
public static final
的變量來引用 - 對象如果有實例變量,應該聲明為private final,並在構造器中初始化
class Season {
//聲明Season對象的屬性:使用 private final 修飾
private final String seasonName;
private final String seasonDesc;
//私有化Season類的構造器,並給對象屬性賦值
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//在類的內部創建當前枚舉類的對象,變量用 public static final 修飾
//public:外部可以使用枚舉類的實例
//static:外部可以使用“類名.對象名”調用
//final:修飾的變量只能指向一個對象,保存的地址值不能更改
public static final Season SPRING = new Season("春天", "春暖花開");
public static final Season SUMMER = new Season("夏天", "烈日炎炎");
public static final Season AUTUMN = new Season("秋天", "秋高氣爽");
public static final Season WINTER = new Season("冬天", "白雪皚皚");
//其他需求
//獲取枚舉類的對象的屬性
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//提供toString()
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
public class SeasonTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring.getSeasonName());
System.out.println(spring);
}
}
2.2 使用enum定義枚舉
jdk1.5之前,枚舉的定義格式太繁瑣,存在很多重復代碼
使用 enum
關鍵字簡化枚舉的定義
-
聲明格式:
[修飾符] enmu 枚舉名{ //實例列表 //其他成員列表 }
枚舉的所有實例必須在其他成員的前面顯式列出(多個實例之間 , 分隔 ; 結尾,只存在實例列表時,最后一個實例后面的 ; 可省略,存在其他成員時,不能省略),它們實際上都是 public static final 修飾的常量對象,不用自己添加修飾符,填上反而會報錯。
枚舉的所有構造器只能使用 private 訪問控制符,並且是隱式私有的。
switch 表達式的case 子句可以直接使用 Enum定義的枚舉的對象的名字。
如果枚舉中只有一個對象,則可以作為單例模式的一種實現方式。
//RED、GREEN、BLUE不是枚舉Color的屬性,而是它的對象
enum Color {
//只有對象列表,可省略最后一個對象后的;
//對象后面沒有“(參數列表)”就是調用無參構造
RED, GREEN, BLUE
}
//SPRING、SUMMER、AUTUMN、WINTER就是枚舉Season的對象
enum Season {
//對象列表必須寫在類的前面,多個對象之間用,隔開,末尾對象;結束
//對象后面有“(參數列表)”就是調用有參構造
SPRING("春天", "春暖花開"),
SUMMER("夏天", "烈日炎炎"),
AUTUMN("秋天", "秋高氣爽"),
WINTER("冬天", "白雪皚皚");
//聲明Season對象的屬性:使用 private final 修飾
private final String seasonDesc;
private final String seasonName;
//私有化Season類的構造器,並給對象屬性賦值
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//其他需求
//獲取枚舉的對象的屬性
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//一般不用重寫toString
}
public class SeasonTest {
public static void main(String[] args) {
Color blue = Color.BLUE;
System.out.println(blue); //BLUE
System.out.println(Color.class.getSuperclass()); //class java.lang.Enum
Season summer = Season.SUMMER;
System.out.println(summer); //SUMMER
System.out.println(Season.class.getSuperclass()); //class java.lang.Enum
Season s = Season.SPRING;
switch(s) {
case SPRING:
System.out.println("春暖花開");
break;
case SUMMER:
System.out.println("烈日炎炎");
break;
case AUTUMN:
System.out.println("秋高氣爽");
break;
case WINTER:
System.out.println("白雪皚皚");
break;
}
}
}
3. 枚舉的隱含直接父類:Enum類
枚舉不能繼承其他類型,因為枚舉類型有一個隱含的直接父類 java.lang.Enum
:它是所有枚舉的父類。
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {...}
Enum類中有一個唯一的構造器:protected Enum(String name, int ordinal)
這個構造器不是程序員手動調用的,是編譯器自動調用,在所有枚舉類型的構造器的首行,並且自動傳入name和ordinal的值。
name:就是枚舉對象名稱
ordinal:就是枚舉對象的序號(在枚舉聲明中的位置),其中初始常量序號為0
3.1 Enum類的主要方法
除了toString方法,都是final修飾的方法,因此都不能重寫。
toString():返回此枚舉常量的名稱,與其在枚舉聲明中的聲明完全相同
String name():返回此枚舉常量的名稱,與其在枚舉聲明中的聲明完全相同,一般用toString()
int ordinal():返回此枚舉常量的序號(在枚舉聲明中的位置),其中初始常量序號為0
- API中沒有的方法,是編譯器幫我們生成的方法:
values()方法:返回枚舉類型的對象數組。該方法可以很方便地遍歷所有的枚舉值。
valueOf(String str):根據枚舉常量的名稱返回對應的枚舉對象。要求字符串必須是枚舉對象的“名字”。如不是,會有運行時異常
//便利枚舉的對象
Season[] seasons = Season.values();
for (Season season : seasons) {
System.out.println(season);
}
//SPRING
//SUMMER
//AUTUMN
//WINTER
Season spring = Season.valueOf("SPRING");
System.out.println(spring); //SPRING
4. 枚舉實現接口
和普通 Java 類一樣,枚舉也可以實現一個或多個接口。
若每個枚舉值在調用實現的接口方法呈現相同的行為,則只要統一實現該方法即可。
若需要每個枚舉值在調用實現的接口方法呈現出不同的行為,則可以讓每個枚舉值分別來實現該方法。
定義接口:
interface MyInter {
void message();
}
interface Info {
void show();
}
枚舉實現接口:
enum Season implements MyInter, Info {
SPRING("春天", "春暖花開") {
@Override
public void show() {
System.out.println("春天在哪里");
}
},
SUMMER("夏天", "烈日炎炎") {
@Override
public void show() {
System.out.println("夏天的風");
}
},
AUTUMN("秋天", "秋高氣爽") {
@Override
public void show() {
System.out.println("秋天不回來");
}
},
WINTER("冬天", "白雪皚皚") {
@Override
public void show() {
System.out.println("大約在冬季");
}
};
private final String seasonDesc;
private final String seasonName;
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//統一實現的重寫方法
@Override
public void message() {
System.out.println("一年四季各不同");
}
}
測試類:
public class SeasonTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
spring.message();
Season summer = Season.SUMMER;
summer.message();
Season autumn = Season.AUTUMN;
autumn.show();
Season winter = Season.WINTER;
winter.show();
}
}
一年四季各不同
一年四季各不同
秋天不回來
大約在冬季
對於同一個方法,兩種重寫方式可任選其一,也可同時存在。分別重寫時,所有的實例都要自己重寫接口中的方法,否則必須添加枚舉的統一重寫方法。同時存在時,實例自己的重寫方法會覆蓋枚舉的統一重寫方法。
枚舉既可以包含具體方法,也可以包含抽象方法。 如果枚舉含有抽象方法,則枚舉的每個實例都必須分別實現該方法。與實現接口類似。