如何使用Java中的Enum类
Java1.5 中出現了枚舉類型。當一個值都在一個固定的范圍內變化,那就可以使用 enum 類型來定義。比如說,一周有七天,一年有四季。
沒有枚舉類的時候,我們用常量來定義一組范圍值的:
public static class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
通過常量定義的方式有這樣幾個缺點:
類型不安全。如 Season 類所示,程序執行過程中接收的是任意一個 int 類型的值,完全可能傳入一個 1 到 4 之外的值,導致錯誤的出現。
一致性差。int 枚舉屬于編譯期常量,編譯完成后,代碼中引用的地方會直接將整數值寫入。也就是說,該 Int 枚舉被修改之后,所有引用它的程序都需要重新編譯。
類型無指意性。Seaon 枚舉值僅僅是一些無任何含義的整數值,調試期間僅僅是一些魔數。
定義一個 enum
《阿里巴巴Java開發手冊(華山版)》中建議我們這樣定義一個 enum 類:
【參考】枚舉類名帶上 Enum 后綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。
說明:枚舉其實就是特殊的類,域成員均為常量,且構造方法被默認強制是私有。
正例:枚舉名字為 ProcessStatusEnum 的成員名稱:SUCCESS / UNKNOWN_REASON。
【推薦】如果變量值僅在一個固定范圍內變化用 enum 類型來定義。
說明:如果存在名稱之外的延伸屬性應使用 enum 類型,下面正例中的數字就是延伸信息,表示一年中的第幾個季節。
由此,我們可以定義一個季節的枚舉類,如下所示:
public enum SeasonEnum {
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
private int seq;
SeasonEnum(int seq) {
this.seq = seq;
}
public int getSeq() {
return seq;
}
}
enum 類
使用 enum 定義的枚舉類默認繼承 java.lang.Enum :
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
}
變量
// enum 實例的名字
private final String name;
// 定義enum實例的順序,從0開始計數
private final int ordinal;
方法
// 返回enum實例的名稱,eg. SeasonEnum.SPRING.name() - output: SPRING
public final String name() { return name;}
// 返回enum實例的順序,eg. SeasonEnum.SPRING.ordinal() - output: 0
public final int ordinal() { return ordinal;}
// enum實例 -> 字符串 eg. SeasonEnum.SPRING.toString() - output: SPRING
public String toString() { return name;}
// 比較是不是一個constant,即兩個enum實例的順序(oridnal)是否相同
public final int compareTo(E o) { ... return self.ordinal - other.ordinal; }
// 比較是不是同一個對象
public final boolean equals(Object other) { return this==other;}
// 返回聲明枚舉常量的類的類對象
public final Class<E> getDeclaringClass(){...}
// 返回指定name的enum實例
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {}
// values()是編譯器產生的一個方法,API中沒有,可以用來遍歷
public static SeasonEnum getSeasonByOrdinal(int seq) {
for (SeasonEnum season: SeasonEnum.values()) {
if(season.getSeq() == seq) {
return season;
}
}
return null;
}
enum 的用法
用法一:定義常量
也就是最開始說的,enum 出現之后,用 enum 來代替常量類型。
public static class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
public enum SeasonEnum {
SPRING, SUMMER, AUTUMN, WINTER;
}
用法二:switch
Java1.5 推出了 enum,Java1.6 支持在 switch 中使用 enum 類型。
public enum OperationUseSwitch {
PLUS, MINUS, TIMES, DIVIDE;
double apply(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
}
// 如果this不屬于上面四種操作符,拋出異常
throw new AssertionError("Unknown operation: " + this);
}
}
用法三:特定于常量的方法實現
特定于常量的方法實現指的是,在 enum 類中定義一個抽象方法,然后各個枚舉常量需要實現這個方法。這樣做的優點在于,相對于 switch 語句,抽象程度更高,每個 enum 實例都需要實現統一的方法,不會漏下。
public enum Operation {
PLUS {
double apply(double x, double y) {
return x + y;
}
},
MINUS {
double apply(double x, double y) {
return x - y;
}
},
TIMES {
double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
double apply(double x, double y) {
return x / y;
}
};
abstract double apply(double x, double y);
}
用法四:實現接口
enum 類都隱式得繼承自 java.lang.Enum,而 Java 只支持單繼承,所有 enum 類不能再繼承其它類,但是可以實現接口。比如用法三中將統一的方法抽象出來,就可以使用接口來實現:
public interface Behavior {
double apply(double x, double y);
}
public enum Operation implements Behavior{
PLUS {
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
public double apply(double x, double y) {
return x - y;
}
},
TIMES {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
public double apply(double x, double y) {
return x / y;
}
};
}
用法五:覆蓋 Enum 的方法
public class Test {
public enum Color {
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);
// 成員變量
private String name;
private int index;
// 構造方法
private Color(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) {
System.out.println(Color.RED.toString());
}
}
EnumSet 和 EnumMap
EnumSet 和 EnumMap 是兩個為枚舉而設計的集合。EnumSet保證集合中的元素不重復;EnumMap中的 key 是enum 類型,而 value 則可以是任意類型。
EnumMap
public class Herb {
public enum Type { ANNUAL, PERENNIAL, BIENNIAL }
private final String name;
private final Type type;
Herb(String name, Type type) {
this.name = name;
this.type = type;
}
@Override public String toString() {
return name;
}
}
public static void main(String[] args) {
?? ?Herb[] garden = { new Herb("Basil", Type.ANNUAL),
?? ??? ??? ?new Herb("Carroway", Type.BIENNIAL),
?? ??? ??? ?new Herb("Dill", Type.ANNUAL),
?? ??? ??? ?new Herb("Lavendar", Type.PERENNIAL),
?? ??? ??? ?new Herb("Parsley", Type.BIENNIAL),
?? ??? ??? ?new Herb("Rosemary", Type.PERENNIAL) };
?? ?// Using an EnumMap to associate data with an enum - Page 162
?? ?Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>(
?? ??? ??? ?Herb.Type.class);
?? ?for (Herb.Type t : Herb.Type.values())
?? ??? ?herbsByType.put(t, new HashSet<Herb>());
?? ?for (Herb h : garden)
?? ??? ?herbsByType.get(h.type).add(h);
?? ?System.out.println(herbsByType);
}
EnumSet
EnumSet 是枚舉類型的高性能 Set 實現,它要求放入它的枚舉常量必須屬于同一枚舉類型。EnumSet 提供了許多工廠方法以便于初始化。
| 方法名稱 | 描述 |
|---|---|
| allOf(Class element type) | 創建一個包含指定枚舉類型中所有枚舉成員的 EnumSet 對象 |
| complementOf(EnumSet s) | 創建一個與指定 EnumSet 對象 s 相同的枚舉類型 EnumSet 對象, 并包含所有 s 中未包含的枚舉成員 |
| copyOf(EnumSet s) | 創建一個與指定 EnumSet 對象 s 相同的枚舉類型 EnumSet 對象, 并與 s 包含相同的枚舉成員 |
| noneOf(<Class elementType) | 創建指定枚舉類型的空 EnumSet 對象 |
| of(E first,e...rest) | 創建包含指定枚舉成員的 EnumSet 對象 |
| range(E from ,E to) | 創建一個 EnumSet 對象,該對象包含了 from 到 to 之間的所有枚 舉成員 |
EnumSet 作為 Set 接口實現,它支持對包含的枚舉常量的遍歷。
for(Operation op:EnumSet.range(Operation.PLUS,Operation.MULTIPLY)) {
doSomeThing(op);
}
參考文獻
W3CSchool-Java枚舉
Java 語言中 Enum 類型的使用介紹
Java 枚舉(enum) 詳解7種常見的用法
Java枚舉 —— 很少被使用,或許是因為真正了解它的人太少了
Java枚舉(enum)詳解:Java聲明枚舉類型、枚舉(enum)類、EnumMap 與 EnumSet
總結
以上是生活随笔為你收集整理的如何使用Java中的Enum类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#下解决DrawImage画出来的Im
- 下一篇: lol虚空之女进化条件是什么 艾欧尼亚V