Java 中的枚举
Enum 是在 Java 1.5 中引入的一种新类型,其字段由一组固定的常量组成。例如,我们可以将方向创建为 Java Enum,其固定字段为 EAST、WEST、NORTH 和 SOUTH。
Java 枚举
在本教程中,我们将学习如何创建枚举。我们还将研究在 Java 中使用枚举的好处以及枚举类型的特性。我们还将通过示例学习如何使用 Java Enum 、枚举valueOf
和values
。EnumSet
EnumMap
Java 枚举示例
Java enum关键字用于创建枚举类型。让我们看一下 java enum 示例程序。
package com.journaldev.enums;
public enum ThreadStates {
START,
RUNNING,
WAITING,
DEAD;
}
在上面的例子中,ThreadStates 是具有固定常量字段 START、RUNNING、WAITING 和 DEAD 的枚举。
Java 枚举与常量
现在让我们看看 Java 枚举比 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 程序中是如何使用的:
/**
* This method shows the benefit of using Enum over Constants
*/
private static void benefitsOfEnumOverConstants() {
//Enum values are fixed
simpleEnumExample(ThreadStates.START);
simpleEnumExample(ThreadStates.WAITING);
simpleEnumExample(ThreadStates.RUNNING);
simpleEnumExample(ThreadStates.DEAD);
simpleEnumExample(null);
simpleConstantsExample(1);
simpleConstantsExample(2);
simpleConstantsExample(3);
simpleConstantsExample(4);
//we can pass any int constant
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");
}
如果我们看上面的例子,我们有两个使用常量的风险,而这可以通过枚举解决。
- 我们可以将任何 int 常量传递给该
simpleConstantsExample
方法,但只能将固定值传递给 simpleEnumExample,因此它提供了类型安全性。 - 我们可以在类中更改 int 常量的值
ThreadStatesConstant
,但上述程序不会引发任何异常。我们的程序可能无法按预期工作,但如果我们更改枚举常量,我们将得到编译时错误,从而消除任何运行时问题的可能性。
Java 枚举方法
现在让我们通过一个例子来了解 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 constructors should always be private.
private ThreadStatesEnum(int i){
priority = i;
}
//Enum can have methods
public int getPriority(){
return this.priority;
}
public void setPriority(int p){
this.priority = p;
}
//Enum can override functions
@Override
public String toString(){
return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
}
@Override
public void close() throws IOException {
System.out.println("Close of Enum");
}
}
Java 枚举要点
以下是 Java 中枚举的一些要点。
- 所有 Java 枚举都隐式扩展了
java.lang.Enum
扩展 Object 类并实现Serializable和Comparable接口的类。所以我们不能扩展枚举中的任何类。 - 由于 enum 是一个关键字,我们不能用它来结束包名,例如,
com.journaldev.enum
它不是一个有效的包名。 - 枚举可以实现接口。如上面的枚举示例所示,它正在实现
Closeable
接口。 - 枚举构造函数始终是私有的。
- 我们不能使用新运算符创建枚举实例。
- 我们可以在 java 枚举中声明抽象方法,然后所有枚举字段都必须实现该抽象方法。上面的例子
getDetail()
是抽象方法,所有枚举字段都实现了它。 - 我们可以在枚举中定义一个方法,枚举字段也可以覆盖它们。例如,
toString()
在枚举中定义了方法,枚举字段 START 已覆盖该方法。 - Java 枚举字段具有命名空间,我们只能使用类名来使用枚举字段,例如
ThreadStates.START
- 枚举可以在switch 语句中使用,我们将在本教程的后面部分看到它的实际应用。
- We can extend existing enum without breaking any existing functionality. For example, we can add a new field NEW in ThreadStates enum without impacting any existing functionality.
- Since enum fields are constants, java best practice is to write them in block letters and underscore for spaces. For example EAST, WEST, EAST_DIRECTION etc.
- Enum constants are implicitly static and final
- Enum constants are final but it’s variable can still be changed. For example, we can use
setPriority()
method to change the priority of enum constants. We will see it in usage in below example. - Since enum constants are final, we can safely compare them using “==” and equals() methods. Both will have the same result.
Java EnumSet, EnumMap, valueOf()
Now we know most of the features of Enum, let’s have a look at Java Enum example program. Then we will learn some more features of an 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();
}
}
Before explaining other important features of enum, let’s see the output of the above program.
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
Important Points
- The
usingEnumMethods()
methods shows how to create an enum object and how we can use its methods. It’s also showing use ofsetPriority(int i)
method to change the variable of enum. usingEnumValueOf()
shows the usage ofjava.util.Enum
valueOf(enumType, name)
through which we can create an enum object from String. It throwsIllegalArgumentException
if the specified enum type has no constant with the specified name, or the specified class object does not represent an enum type. It also throwsNullPointerException
if any of the arguments are null.usingEnumValues()
method shows the usage of values() method that returns an array containing all of the values of the enum in the order they are declared. Note that this method is automatically generated by java compiler for every enum. You won’t find values() implementation injava.util.Enum
class.- The
usingEnumInSwitch()
method shows how to use enum constants in switch case. usingEnumMap()
method shows use of java.util.EnumMap, which is introduced in Java 1.5 Collections Framework.EnumMap
is Map implementation for use with enum type keys. All of the keys in an enum map must come from a single enum type that is specified, explicitly or implicitly, when the map is created. We can’t use null as key for EnumMap and EnumMap is not synchronized.usingEnumSet()
method shows use of java.util.EnumSet, which is Set implementation for use with enum types. All of the elements in an enum set must come from a single enum type that is specified, explicitly or implicitly, when the set is created. EnumSet is not synchronized and null elements are not allowed. It also provides some useful methods likecopyOf(Collection<E> c)
,of(E first, E... rest)
andcomplementOf(EnumSet<E> s)
.
You can checkout all the examples from our GitHub Repository.
Reference: Oracle Doc