目錄
Java 枚舉(enum)概述
1、Java JDK 1.5 新增的 enum 關鍵詞,可以定義枚舉類,如 public enum WeekEnum { }.
2、使用 enum 定義後的枚舉類在編譯後默認繼承 java.lang.Enum 類,而不是普通的繼承 Object 類。由於 Java 不支持多繼承,所以枚舉不能再顯示的繼承其他類,但是可以實現接口。
3、Enum 類默認實現了 Java.lang.Comparable 接口與 Serializable 接口
4、Enum 類重寫了 toString 方法,返回聲明中包含的此枚舉常量的名稱。
5、enum 聲明後,該類會被編譯器加上 final 聲明(如同 String),故枚舉無法被繼承。
6、枚舉類內部定義的枚舉值就是該類的實例,且必須在第一行定義,當類初始化時,這些枚舉值會被實例化,互相以逗號分隔。 如 "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday"
7、每個枚舉類都有一個 values 方法,該方法可以遍歷枚舉類的所有實例.
8、枚舉規定好了指定的取值範圍,所有的內容只能從指定的範圍中取得。
9、枚舉是一種類型,用於定義變量,以限制變量的賦值;通過 "枚舉名.值" 取得枚舉值,每個值都是一個 Enum 實例
10、枚舉是一個特殊的類,可以定義自己的 field、方法、可以實現接口,也可以定義自己的構造器.
11、枚舉類的構造方法默認用 private 修飾的,且不能出現 public 構造方法,因此無法 new 一個枚舉對
13、實際編程中往往存在着這樣的 "數據集",它們的數值是穩定的、元素個數是有限的,例如星期一到星期日,春夏秋冬四季等等,很多時候大家選擇使用常量。 JDK 1.5 開始有了枚舉,其實可以把相關的常量放到一個枚舉類型裏,枚舉提供了比常量更多的方法,使用起來更加方便。
枚舉常量
1、定義枚舉
/**
* 星期,一週的枚舉
*/
public enum WeekEnum {
/**
* 最簡單的枚舉形式,使用逗號分隔,結尾分號此時可以省略
* 每一個值都代表當前的枚舉實例,通過 枚舉名.值 獲取
*/
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
2、測試枚舉:
import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
public static void main(String[] args) {
//類似靜態類,也是 枚舉名.值 直接獲取,每個值都是 Enum 實例
WeekEnum sundayEnum = WeekEnum.Sunday;
//因爲 Enum 重寫了 toString 方法,方法中返回 name 屬性
System.out.println("WeekEnum.Sunday=" + sundayEnum.toString());//輸出 Sunday
//返回此枚舉常量的名稱,與其枚舉聲明中聲明的完全相同,看源碼一目瞭然
System.out.println("weekEnum.name()=" + sundayEnum.name());//輸出 Sunday
switch (sundayEnum) {
case Monday:
System.out.println("星期1");
break;
case Friday:
System.out.println("星期5");
break;
case Sunday:
System.out.println("星期7");//會輸出
}
//每個枚舉類都有一個 values 方法,可以遍歷枚舉類的所有 Enum 實例.
WeekEnum[] weekEnums = WeekEnum.values();
for (WeekEnum weekEnum_loop : weekEnums) {
//ordinal():返回此枚舉常數的序號(就是在枚舉聲明中的位置,從0開始)。
System.out.print(weekEnum_loop.ordinal() + ":" + weekEnum_loop.name() + " ");
}
/**
* compareTo:看源碼一目瞭然,就是根據序號 ordinal 對比同類型的枚舉值是否相等
* 自己的序號減去對比項的序號,如果爲0則相等,否則就是正負數。注意只能對比相同枚舉類型
*/
WeekEnum mondayEnum = WeekEnum.Monday;
int flag1 = sundayEnum.compareTo(mondayEnum);
int flag2 = sundayEnum.compareTo(WeekEnum.Sunday);
System.out.println("\n" + flag1 + "、" + flag2);//輸出 6、0
}
}
屬性與方法
1、枚舉像普通的類一樣可以添加屬性和方法(包括靜態或非靜態的屬性或方法)。注意枚舉值要寫在最前面,且以分號結尾,否則編譯出錯。
/**
* 星期,一週的枚舉
*/
public enum WeekEnum {
//枚舉值寫在最前面,有其他內容時,必須以分號結尾
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;
//枚舉對象得通過上面得值來獲取,其餘得編碼和普通的 類 區別不大
private Integer id;
public static String summary;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
2、測試代碼:
import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
public static void main(String[] args) {
//枚舉名.值 獲取實例。獲取到實例後,其餘得編碼和普通的 類 區別不大
WeekEnum sundayEnum = WeekEnum.Sunday;
Integer id = sundayEnum.getId();//此時因爲屬性沒有賦值,所以輸出:null、null
System.out.println(id + "、" + WeekEnum.summary);
sundayEnum.setId(9527);//給id屬性賦值
id = sundayEnum.getId();//重新取值
WeekEnum.summary = "梅山龍宮";//爲靜態屬性賦值。如果枚舉中有靜態方法,則也是同理 枚舉枚舉名.靜態方法名
System.out.println(id + "、" + WeekEnum.summary);//輸出:9527、梅山龍宮
}
}
枚舉參數
1、枚舉常量後面可以接括號定義枚舉參數,這些參數會通過對應的構造器自動給屬性賦值。"枚舉參數 -> 對應的構造器 -> 屬性" 完成賦值
/**
* 星期,一週的枚舉
*/
public enum WeekEnum {
//枚舉值寫在最前面,有其他內容時,必須以分號結尾。
//因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
Monday(1, "星期一"),//匹配兩個參數的構造器創建實例
Tuesday(2, "星期二"),
Wednesday(3, "星期三"),
Thursday(4, "星期四"),
Friday(5, "星期五"),
Saturday(6, "星期六"),
Sunday(7, "星期天", "週末");//匹配三個參數的構造器創建實例
//屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
private Integer code;
private String name;
private String ext;
//構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
WeekEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
WeekEnum(Integer code, String name, String ext) {
this.code = code;
this.name = name;
this.ext = ext;
}
//因爲枚舉常量的參數都是通過內部私有的構造器賦值的,無法通過外部賦值,所以沒必要提供 setter方法
//但是可以提供 getter 方法來獲取枚舉參數值
public Integer getCode() {
return code;
}
public String getName() {
return name;
}
public String getExt() {
return ext;
}
}
2、測試代碼:
import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
public static void main(String[] args) {
//枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
WeekEnum sundayEnum = WeekEnum.Sunday;
WeekEnum mondayEnum = WeekEnum.Monday;
//上面的實例包含了自己枚舉參數,所以可以通過 getter 方法獲取
System.out.println(sundayEnum.getCode() + "->" + sundayEnum.getName() + "->" + sundayEnum.getExt());
System.out.println(mondayEnum.getCode() + "->" + mondayEnum.getName() + "->" + mondayEnum.getExt());
//輸出:7->星期天->週末
//輸出:1->星期一->null。因爲星期一沒有提供 ext 參數,所以爲 null
}
}
2、總結:
枚舉的構造器私有,每一個枚舉值都是一個枚舉實例,編譯後自動產生。枚舉值的參數與構造器的參數相對應,即枚舉值後面沒跟參數時,構造器也是無參構造,
枚舉值後面跟參數時,必須要有參數個數且類型相同的構造器與之對應,以及設置相應的成員變量。編譯構建實例的順序是:枚舉值後面的實參值->找到對應的構造方法->注入給相應的成員變量。因爲構造器可以重載,所以枚舉值後面的參數可以不同,包括類型與個數。
每個枚舉值既可以調用自己獨有的屬性,即後面的參數值,也可以調用公共的屬性,即可調用自己下面獨有的方法,也可調用公共的方法。當枚舉值/枚舉常量沒有帶參數時,則沒必要要構造器,反之如果枚舉值有參數,則必須有構造器與之對應
實現接口
1、先準備一個接口:
import java.util.Map;
public interface WeekEnumInterface {
Integer getCode();
String getName();
Map<String, Object> getDataMap();
}
2、定義枚舉並實現接口
import java.util.HashMap;
import java.util.Map;
/**
* 星期,一週的枚舉
* 枚舉 enum 默認已經繼承了 Enum 類,所以無法再繼承,但是可以實現接口
*/
public enum WeekEnum implements WeekEnumInterface {
//枚舉值寫在最前面,有其他內容時,必須以分號結尾。
//因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
Monday(1, "星期一"),//匹配兩個參數的構造器創建實例
Tuesday(2, "星期二"),
Wednesday(3, "星期三"),
Thursday(4, "星期四"),
Friday(5, "星期五"),
Saturday(6, "星期六"),
Sunday(7, "星期天");
//屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
private Integer code;
private String name;
//構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
WeekEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getName() {
return name;
}
//將整個枚舉參數轉爲 Map 結構
@Override
public Map<String, Object> getDataMap() {
Map<String, Object> dataMap = new HashMap<>(WeekEnum.values().length);
for (WeekEnum weekEnum : WeekEnum.values()) {
dataMap.put(weekEnum.code + "", weekEnum.name);
}
return dataMap;
}
}
3、測試代碼:
import wmx.com.springboothello.enum_wmx.WeekEnum;
import java.util.Map;
public class Test {
public static void main(String[] args) {
//枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
WeekEnum sundayEnum = WeekEnum.Sunday;
System.out.println(sundayEnum.getCode() + " - " + sundayEnum.getName());
//
Map<String, Object> dataMap = sundayEnum.getDataMap();
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
}
抽象方法
1、枚舉中可以有抽象方法,且由枚舉值/枚舉常量提供方法實現。枚舉類如下:
/**
* 星期,一週的枚舉
* 枚舉 enum 默認已經繼承了 Enum 類,所以無法再繼承,但是可以實現接口
*/
public enum WeekEnum {
//枚舉值寫在最前面,有其他內容時,必須以分號結尾。
//因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
Monday(1, "星期一") {
@Override
public String toSplitString() {
return Monday.code + "," + Monday.name;
}
},//匹配兩個參數的構造器創建實例
Tuesday(2, "星期二") {
@Override
public String toSplitString() {
return Tuesday.getCode() + "," + Tuesday.getName();
}
};
//屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
private Integer code;
private String name;
//構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
WeekEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public Integer getCode() {
return code;
}
public String getName() {
return name;
}
//方法要是 public 修飾外部才能調用
public abstract String toSplitString();
}
2、測試代碼:
import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
public static void main(String[] args) {
//枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
WeekEnum mondayEnum = WeekEnum.Monday;
WeekEnum tuesdayEnum = WeekEnum.Tuesday;
System.out.println(mondayEnum.getCode() + " - " + mondayEnum.getName());//輸出:1 - 星期一
System.out.println(tuesdayEnum.getCode() + " - " + tuesdayEnum.getName());//輸出:2 - 星期二
System.out.println(mondayEnum.toSplitString());//輸出:1,星期一
System.out.println(tuesdayEnum.toSplitString());//輸出:2,星期二
}
}