Java中的枚举
在Java 1.5中引入了枚举作为一种新的类型,其字段由一组固定的常量组成。例如,我们可以创建一个作为Java枚举的方向,其固定字段为东(EAST)、西(WEST)、北(NORTH)和南(SOUTH)。
Java枚举

Java枚举示例
Java的enum关键字用于创建枚举类型。让我们来看一下Java枚举例子程序。
package com.Olivia.enums;
public enum ThreadStates {
START,
RUNNING,
WAITING,
DEAD;
}
在上述示例中,ThreadStates是具有固定常量字段START、RUNNING、WAITING和DEAD的枚举类型。
Java 枚举 vs 常量
现在让我们来看看Java中的枚举类型比普通常量字段更好的地方。让我们在Java中创建一个类似的常量类。
package com.Olivia.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方法,因此它提供了类型安全性。
- 我们可以更改ThreadStatesConstant类中int常量的值,但是以上程序不会抛出任何异常。我们的程序可能无法按预期工作,但是如果我们更改枚举常量,将会得到编译时错误,从而消除了任何可能的运行时问题。
Java 枚举方法
现在让我们通过一个例子来了解Java枚举的更多特性。
package com.Olivia.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.Olivia.enum是一个无效的包名。
-
- 枚举可以实现接口。就像上面的枚举示例中,它实现了Closeable接口。
-
- 枚举的构造函数总是私有的。
-
- 我们不能使用new运算符创建枚举的实例。
-
- 在java枚举中,我们可以声明抽象方法,然后所有的枚举字段必须实现这个抽象方法。在上面的例子中,getDetail()是抽象方法,所有的枚举字段都实现了它。
-
- 我们可以在枚举中定义方法,枚举字段也可以重写它们。例如,toString()方法在枚举中被定义,枚举字段START对其进行了重写。
-
- Java枚举字段具有命名空间,我们只能使用类名和枚举字段一起使用,比如ThreadStates.START。
-
- 枚举可以在switch语句中使用,我们将在本教程的后面部分看到它的使用。
-
- 我们可以扩展现有的枚举而不破坏任何现有的功能。例如,我们可以在ThreadStates枚举中添加一个新的字段NEW,而不影响任何现有的功能。
-
- 由于枚举字段是常量,java的最佳实践是用大写字母和下划线代替空格进行命名。例如EAST,WEST,EAST_DIRECTION等。
-
- 枚举常量隐式地是静态和最终的。
-
- 枚举常量是最终的,但它的变量仍然可以被修改。例如,我们可以使用setPriority()方法来更改枚举常量的优先级。我们将在下面的例子中看到它的使用。
- 由于枚举常量是最终的,我们可以安全地使用“==”和equals()方法进行比较。两者将得到相同的结果。
Java EnumSet, EnumMap, valueOf() 在Java中的等价功能是 EnumSet、EnumMap 和 valueOf()。
现在我们了解了Enum的大多数特性,让我们来看一下Java的枚举示例程序。然后我们将学习一些枚举类型的更多特性。
package com.Olivia.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();
}
}
在解释枚举的其他重要特性之前,让我们先看一下上述程序的输出结果。
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。如果任何参数为空,还会抛出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的使用,它是用于枚举类型的Set实现。枚举集中的所有元素必须来自于在创建集合时指定的单个枚举类型,显式或隐式。EnumSet不是同步的,也不允许空元素。它还提供了一些有用的方法,如copyOf(Collection c),of(E first, E… rest)和complementOf(EnumSet s)。
您可以查看我们 GitHub 资料库中的所有示例。
参考:Oracle文档