Enum在Java 1.5中作为一种新类型被引入,其字段由一组固定的常量组成。例如,我们可以创建代表方向的Java Enum,其固定字段为EAST、WEST、NORTH和SOUTH。
Java Enum
在本教程中,我们将学习如何创建Enum。我们还将探讨在Java中使用enums的好处以及enum类型的特性。我们还将学习使用Java Enum的
valueOf
、enum values
、EnumSet
和EnumMap
,并附有示例。
Java Enum示例
Java enum关键字用于创建enum类型。让我们看一下Java Enum示例程序。
package com.journaldev.enums;
public enum ThreadStates {
START,
RUNNING,
WAITING,
DEAD;
}
在上面的例子中,ThreadStates是具有固定常量字段START、RUNNING、WAITING和DEAD的enum。
Java Enum vs 常量
现在让我们看看Java Enum如何优于Java类中的普通常量字段。让我们在Java中创建一个类似的常量类。
package com.journaldev.enums;
public class ThreadStatesConstant {
public static final int START = 1;
public static final int WAITING = 2;
public static final int RUNNING = 3;
public static final int DEAD = 4;
}
現在讓我們看看在Java程序中如何使用enum和常量:
/**
* This method shows the benefit of using Enum over Constants
*/
private static void benefitsOfEnumOverConstants() {
//Enum值是固定的
simpleEnumExample(ThreadStates.START);
simpleEnumExample(ThreadStates.WAITING);
simpleEnumExample(ThreadStates.RUNNING);
simpleEnumExample(ThreadStates.DEAD);
simpleEnumExample(null);
simpleConstantsExample(1);
simpleConstantsExample(2);
simpleConstantsExample(3);
simpleConstantsExample(4);
//我們可以傳遞任何int常量
simpleConstantsExample(5);
}
private static void simpleEnumExample(ThreadStates th) {
if(th == ThreadStates.START) System.out.println("Thread started");
else if (th == ThreadStates.WAITING) System.out.println("Thread is waiting");
else if (th == ThreadStates.RUNNING) System.out.println("Thread is running");
else System.out.println("Thread is dead");
}
private static void simpleConstantsExample(int i) {
if(i == ThreadStatesConstant.START) System.out.println("Thread started");
else if (i == ThreadStatesConstant.WAITING) System.out.println("Thread is waiting");
else if (i == ThreadStatesConstant.RUNNING) System.out.println("Thread is running");
else System.out.println("Thread is dead");
}
如果我們看上面的例子,使用常量有兩個風險,這些風險可以通過enum來解決。
- 我們可以將任何int常量傳遞給
simpleConstantsExample
方法,但我們只能將固定值傳遞給simpleEnumExample,因此它提供了類型安全性。 - 我們可以更改
ThreadStatesConstant
類中int常量的值,但上面的程序不會拋出任何異常。我們的程序可能不會按預期工作,但如果我們更改enum常量,則會獲得編譯時錯誤,從而消除了任何可能的運行時問題。
Java Enum方法
現在讓我們通過一個例子來看看Java enum的更多功能。
package com.journaldev.enums;
import java.io.Closeable;
import java.io.IOException;
/**
* This Enum example shows all the things we can do with Enum types
*
*/
public enum ThreadStatesEnum implements Closeable{
START(1){
@Override
public String toString(){
return "START implementation. Priority="+getPriority();
}
@Override
public String getDetail() {
return "START";
}
},
RUNNING(2){
@Override
public String getDetail() {
return "RUNNING";
}
},
WAITING(3){
@Override
public String getDetail() {
return "WAITING";
}
},
DEAD(4){
@Override
public String getDetail() {
return "DEAD";
}
};
private int priority;
public abstract String getDetail();
//Enum構造函數應始終是私有的。
private ThreadStatesEnum(int i){
priority = i;
}
//Enum可以有方法
public int getPriority(){
return this.priority;
}
public void setPriority(int p){
this.priority = p;
}
//Enum可以覆蓋函數
@Override
public String toString(){
return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
}
@Override
public void close() throws IOException {
System.out.println("Close of Enum");
}
}
Java Enum重要注意事項
以下是Java中枚舉類的一些重要注意事項。
- 所有Java枚舉都隱式擴展`java.lang.Enum`類別,該類別擴展Object類別並實現`Serializable`和`Comparable`介面。因此,我們無法在枚舉中擴展任何類別。
- 由於enum是關鍵字,我們不能以它結尾作為包名,例如`com.journaldev.enum`不是有效的包名。
- 枚舉可以實現介面。就像上面的枚舉示例一樣,它實現了`Closeable`介面。
- 枚舉的構造函數始終是私有的。
- 我們不能使用new運算符創建枚舉的實例。
- 我們可以在Java枚舉中聲明抽象方法,然後所有的枚舉字段必須實現該抽象方法。在上面的例子中,`getDetail()`是抽象方法,所有的枚舉字段都已實現它。
- 我們可以在枚舉中定義一個方法,枚舉字段也可以覆蓋它們。例如,`toString()`方法在枚舉中被定義,枚舉字段START已覆蓋它。
- Java枚舉字段具有命名空間,我們只能使用類名與枚舉字段,如`ThreadStates.START`。
- 枚舉可以在switch語句中使用,我們將在本教程的後部看到它的應用。
- 我們可以擴展現有的列舉(enum)而不會破壞任何現有功能。例如,我們可以在ThreadStates列舉(enum)中添加一個新字段NEW,而不會影響任何現有功能。
- 由於列舉(enum)字段是常量,Java最佳實踐是將它們寫成大寫字母並用底線表示空格。例如EAST、WEST、EAST_DIRECTION等。
- 列舉(enum)常量隱式地是靜態(static)和最終(final)的。
- 列舉(enum)常量是最終(final)的,但它的變量仍然可以更改。例如,我們可以使用
setPriority()
方法來更改列舉(enum)常量的優先級。我們將在下面的示例中看到它的使用。 - 由於列舉(enum)常量是最終(final)的,我們可以安全地使用“==”和equals()方法來比較它們。兩者將產生相同的結果。
Java EnumSet,EnumMap,valueOf()
現在我們知道列舉(enum)的大多數特性,讓我們來看一個Java列舉(enum)示例程序。然後我們將學習一些列舉(enum)的更多特性。
package com.journaldev.enums;
import java.io.IOException;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Set;
public class JavaEnumExamples {
public static void main(String[] args) throws IOException {
usingEnumMethods();
usingEnumValueOf();
usingEnumValues();
usingEnumInSwitch(ThreadStatesEnum.START);
usingEnumInSwitch(ThreadStatesEnum.DEAD);
usingEnumMap();
usingEnumSet();
}
private static void usingEnumSet() {
EnumSet enumSet = EnumSet.allOf(ThreadStatesEnum.class);
for(ThreadStatesEnum tsenum : enumSet){
System.out.println("Using EnumSet, priority = "+tsenum.getPriority());
}
}
private static void usingEnumMap() {
EnumMap<ThreadStatesEnum, String> enumMap = new EnumMap<ThreadStatesEnum,String>(ThreadStatesEnum.class);
enumMap.put(ThreadStatesEnum.START, "Thread is started");
enumMap.put(ThreadStatesEnum.RUNNING, "Thread is running");
enumMap.put(ThreadStatesEnum.WAITING, "Thread is waiting");
enumMap.put(ThreadStatesEnum.DEAD, "Thread is dead");
Set keySet = enumMap.keySet();
for(ThreadStatesEnum key : keySet){
System.out.println("key="+key.toString()+":: value="+enumMap.get(key));
}
}
private static void usingEnumInSwitch(ThreadStatesEnum th) {
switch (th){
case START:
System.out.println("START thread");
break;
case WAITING:
System.out.println("WAITING thread");
break;
case RUNNING:
System.out.println("RUNNING thread");
break;
case DEAD:
System.out.println("DEAD thread");
}
}
private static void usingEnumValues() {
ThreadStatesEnum[] thArray = ThreadStatesEnum.values();
for(ThreadStatesEnum th : thArray){
System.out.println(th.toString() + "::priority="+th.getPriority());
}
}
private static void usingEnumValueOf() {
ThreadStatesEnum th = Enum.valueOf(ThreadStatesEnum.class, "START");
System.out.println("th priority="+th.getPriority());
}
private static void usingEnumMethods() throws IOException {
ThreadStatesEnum thc = ThreadStatesEnum.DEAD;
System.out.println("priority is:"+thc.getPriority());
thc = ThreadStatesEnum.DEAD;
System.out.println("Using overriden method."+thc.toString());
thc = ThreadStatesEnum.START;
System.out.println("Using overriden method."+thc.toString());
thc.setPriority(10);
System.out.println("Enum Constant variable changed priority value="+thc.getPriority());
thc.close();
}
}
在解釋列舉(enum)的其他重要特性之前,讓我們看一下上述程序的輸出。
priority is:4
Using overriden method.Default ThreadStatesConstructors implementation. Priority=4
Using overriden method.START implementation. Priority=1
Enum Constant variable changed priority value=10
Close of Enum
th priority=10
START implementation. Priority=10::priority=10
Default ThreadStatesConstructors implementation. Priority=2::priority=2
Default ThreadStatesConstructors implementation. Priority=3::priority=3
Default ThreadStatesConstructors implementation. Priority=4::priority=4
START thread
DEAD thread
key=START:: value=Thread is started
key=RUNNING:: value=Thread is running
key=WAITING:: value=Thread is waiting
key=DEAD:: value=Thread is dead
Using EnumSet, priority = 10
Using EnumSet, priority = 2
Using EnumSet, priority = 3
Using EnumSet, priority = 4
重要要點
usingEnumMethods()
方法顯示了如何創建枚舉對象以及如何使用其方法。它還展示了使用setPriority(int i)
方法來更改枚舉變量的用法。usingEnumValueOf()
顯示了使用java.util.Enum
的valueOf(enumType, name)
方法,通過該方法我們可以從字符串創建枚舉對象。如果指定的枚舉類型中沒有具有指定名稱的常量,或者指定的類對象不表示枚舉類型,則會拋出IllegalArgumentException
。如果任何參數為 null,則還會拋出NullPointerException
。usingEnumValues()
方法顯示了使用 values() 方法的用法,該方法返回按宣告順序包含枚舉所有值的數組。請注意,這個方法是由Java編譯器自動為每個枚舉生成的。您在java.util.Enum
類中找不到 values() 的實現。usingEnumInSwitch()
方法展示了如何在 switch case 中使用枚舉常量。usingEnumMap()
方法展示了使用 java.util.EnumMap,它是Java 1.5集合框架中引入的。EnumMap
是用於枚舉類型鍵的 Map 實現。枚舉映射中的所有鍵必須來自於單個枚舉類型,該類型在創建映射時被指定,明確地或隱式地。我們不能將 null 用作 EnumMap 的鍵,而且 EnumMap 不是同步的。usingEnumSet()
方法展示了使用 java.util.EnumSet 的示例,這是一個用於 enum 類型的 Set 實現。枚舉集合中的所有元素必須來自於指定的單個枚舉類型,該類型在創建集合時被明確或隱式地指定。EnumSet 不是同步的,且不允許空元素。它還提供了一些有用的方法,如copyOf(Collection<E> c)
、of(E first, E... rest)
和complementOf(EnumSet<E> s)
。
您可以從我們的 GitHub 存儲庫 中查看所有示例。
參考: Oracle 文檔
Source:
https://www.digitalocean.com/community/tutorials/java-enum