Java enum列舉在實際專案中的常用方法
阿新 • • 發佈:2020-03-06
> 在專案實際開發過程中,經常會遇到對某些固定的值、字典項的定義的需求,很多專案經常使用常量來定義,其實在jdk1.5就已經引入了列舉,使用列舉可以更好的解決這類需求,本文主要記錄列舉的優勢以及經常在專案中使用的方法。
# 知識點
* **列舉類命名**
列舉類的命名通常需要Enum為字尾,列舉成員名稱需要全大寫,單詞間用下劃線隔開。
* **列舉類不允許使用 extends 關鍵字**
列舉類預設會繼承java.lang.Enum,由於java是單繼承,所以在定義列舉類時不允許再繼承其他類,但可以實現多個介面
* **列舉的比較可以直接使用 ==**
列舉是不允許被new出來的,列舉類裡的建構函式都限定為私有化,是不允許使用public定義建構函式的。列舉的賦值,如果是同一個元素,則會指向同一個地址,所以是可以直接使用==的,當然在Enum類中,重寫了equals方法(如下圖),所以也是可以用equals來判斷。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200229173048738.png)
* **列舉常用方法**
|方法名| 用途 |
|--|--|
| name() | 返回列舉常量名 |
| toString() | 返回列舉常量名 |
| values() | 返回列舉成員陣列 |
| valueOf() | 通過列舉常量名返回列舉 |
| ordinal() | 返回列舉常量在enum宣告中的位置,位置是從0開始計數的 |
* **列舉在switch中的使用**
列舉在switch中的使用,優勢在於能控制case的範圍(看以下例項),並且在idea中有相關提示
* **列舉在單例模式的使用**
首先使用列舉類實現單例模式,寫法相當簡單,看最後的例項;其次列舉是執行緒安全、單一例項(由於構造方法都是私有的,不能被new)
# 例項
## 1. 最簡單的列舉
> 在專案中經常會遇到一些固定值的定義,以往都是用常量來定義,以下用例項說明,為啥列舉的方式優於常量的方式,以下就以季節的定義為例
### 1.1 使用常量來實現
```java
/**
* @Description: 季節常量定義
*/
public class SeasonConst {
/**
* 春季
*/
public static final String SPRING = "SPRING";
/**
* 夏季
*/
public static final String SUMMER = "SUMMER";
/**
* 秋季
*/
public static final String AUTUMN = "AUTUMN";
/**
* 冬季
*/
public static final String WINTER = "WINTER";
}
```
**以上例項雖然實現了功能,但有兩點比較明顯的缺點:**
1. 常量值容易寫錯(特別是複製黏貼,但是忘記改對應的值,導致系統出bug),idea不會給任何提示。
比如,某人粗心,在複製黏貼程式碼時變成(將春季、夏季都定義成春季了):
```java
/**
* 春季
*/
public static final String SPRING = "SPRING";
/**
* 夏季
*/
public static final String SUMMER = "SPRING";
```
2. 如果我想知道一年總共多少個季節,咋整?用常量定義的類,有點捉襟見肘
### 1.2 使用列舉來實現,可以實現常量的所有功能,並能輕鬆解決以上提出的常量的兩個缺點
* 定義列舉類SeasonEnum
```java
public enum SeasonEnum {
/**
* 春季
*/
SPRING,
/**
* 夏季
*/
SUMMER,
/**
* 秋季
*/
AUTUMN,
/**
* 冬季
*/
WINTER
}
```
**在SeasonEnum列舉類中,如果定義兩個 SPRING,編譯器會直接報錯,很好解決了常量的第一個缺點**
* 該列舉類的使用(1、獲取列舉值的名稱;2、列舉判斷的使用;3、列舉迴圈的使用。**通過列舉的迴圈,很好解決了常量的第二個缺點**;)
```java
//獲取列舉值的名稱,與toString得到的結果一樣
String spring = SeasonEnum.SPRING.name();
System.out.println(spring);
//列舉判斷的使用
SeasonEnum springEnum1 = SeasonEnum.SPRING;
SeasonEnum springEnum2 = SeasonEnum.SPRING;
SeasonEnum summerEnum3 = SeasonEnum.SUMMER;
//由於springEnum1、springEnum2都指向SPRING,所以輸出true
System.out.println("springEnum1 == springEnum2:" + (springEnum1 == springEnum2));
//由於springEnum1指向SPRING、summerEnum3指向SUMMER,所以輸出false
System.out.println("springEnum1 == summerEnum3:" + (springEnum1 == summerEnum3));
//迴圈列舉,列印列舉類中的所有列舉成員
SeasonEnum[] seasonEnums = SeasonEnum.values();
for (SeasonEnum seasonEnum : seasonEnums) {
System.out.println(seasonEnum.name());
}
```
* 列舉在switch中的使用,如果case後跟不存在SeasonEnum類中的列舉(比如 case OTHER),則編譯器會報錯
```java
String enumName = "SPRING";
SeasonEnum seasonEnum = SeasonEnum.valueOf(enumName);
switch (seasonEnum){
case SPRING:
System.out.println(seasonEnum.name());
break;
case SUMMER:
System.out.println(seasonEnum.name());
break;
case AUTUMN:
System.out.println(seasonEnum.name());
break;
case WINTER:
System.out.println(seasonEnum.name());
break;
default:
System.out.println("other");
}
```
## 2.在列舉中使用自定義屬性和方法
> 專案中經常也會遇到一些字典項的定義,比如性別,包含存入資料庫中的值,以及顯示在頁面上的值。以下通過例項來實現性別字典。
* 定義SexEnum(注意看程式碼中的註解)
```java
public enum SexEnum {
MAN("man","男"),
WOMEN("women","女");
private String sexCode;
private String sexName;
/**
* 自定義建構函式,以完成列舉對sexCode、sexName賦值
* @param sexCode
* @param sexName
*/
SexEnum(String sexCode,String sexName){
this.sexCode = sexCode;
this.sexName = sexName;
}
/**
* 獲取sexCode
* @return
*/
public String getSexCode() {
return sexCode;
}
/**
* 獲取sexName
* @return
*/
public String getSexName() {
return sexName;
}
/**
* 專案中經常會根據code,轉換成對應的name
* 所以這裡自定義方法,根據sexCode獲取sexName
* 通過迴圈enum來實現
* @param sexCode
* @return
*/
public static String getSexNameByCode(String sexCode){
String sexName = "sexCode不存在";
SexEnum[] sexEnums = SexEnum.values();
for (SexEnum sexEnum : sexEnums) {
if(sexEnum.getSexCode().equals(sexCode)){
sexName = sexEnum.getSexName();
break;
}
}
return sexName;
}
/**
* 專案中也有根據name,轉換成對應的code
* 所以這裡自定義方法,根據sexName獲取sexCode
* 通過迴圈enum來實現
* @param sexName
* @return
*/
public static String getSexCodeByName(String sexName){
String sexCode = "sexName不存在";
SexEnum[] sexEnums = SexEnum.values();
for (SexEnum sexEnum : sexEnums) {
if(sexEnum.getSexName().equals(sexName)){
sexCode = sexEnum.getSexCode();
break;
}
}
return sexCode;
}
/**
* 根據sexCode獲取SexEnum,在switch中使用
* 通過迴圈enum來實現
* @param sexCode
* @return
*/
public static SexEnum getEnumByCode(String sexCode){
SexEnum[] sexEnums = SexEnum.values();
for (SexEnum sexEnum : sexEnums) {
if(sexEnum.getSexCode().equals(sexCode)){
return sexEnum;
}
}
return null;
}
/**
* 重寫toString方法
* @return
*/
@Override
public String toString() {
return this.sexCode + ":" + this.sexName;
}
}
```
* SexEnum列舉類的使用
```java
public class EnumMain {
public static void main(String[] args){
//迴圈帶自定義方法的列舉
SexEnum[] sexEnums = SexEnum.values();
for (SexEnum sexEnum : sexEnums) {
System.out.println("sexCode:"+sexEnum.getSexCode());
System.out.println("sexName:"+sexEnum.getSexName());
System.out.println("sexCode:sexName="+sexEnum.toString());
}
//根據sexCode獲取sexName
String sexName = SexEnum.getSexNameByCode("women");
System.out.println("根據sexCode獲取sexName:" + sexName);
//根據sexName獲取sexCode
String sexCode = SexEnum.getSexCodeByName("男");
System.out.println("根據sexName獲取sexCode:" + sexCode);
//通過傳入的sexCode使用switch
testSexEnumSwitch("women");
}
/**
* 實際專案中,基本上都是傳sexCode的,所以這裡也根據傳入的sexCode,使用switch方法
* @param sexCode
*/
private static void testSexEnumSwitch(String sexCode){
//自定義getEnumByCode方法,通過sexCode獲取SexEnum
SexEnum sexEnum = SexEnum.getEnumByCode(sexCode);
switch (sexEnum){
case MAN:
System.out.println(sexEnum.toString());
break;
case WOMEN:
System.out.println(sexEnum.toString());
break;
default:
System.out.println("other");
}
}
}
```
## 3.通過列舉實現單例
* 單例定義
```java
public enum Singleton {
INSTALL;
/**
* 自定義方法
*/
public void yourMethod(){
System.out.println("do your business");
}
}
```
* 呼叫方法
```java
Singleton.INSTALL.yourMethod();
```
# 原始碼獲取
以上示例都可以通過[我的GitHub](https://github.com/simonxie/javase-demo)獲取完整的程式碼,[點選獲取](https://github.com/simonxie/javase-demo/tree/master/src/main/java/com/simon/enu