Java中的枚举

时间:2020-02-23 14:36:30  来源:igfitidea点击:

Enum在Java 1.5中作为一种新类型引入,其字段由一组固定的常量组成。
例如,我们可以将Java Enum创建为带有固定字段(例如EAST,WEST,NORTH和SOUTH)的路线。

Java枚举

在本教程中,我们将学习如何创建枚举。
我们还将探讨在Java中使用枚举的好处以及枚举类型的功能。
我们还将通过示例使用Java Enum valuevalue,枚举values,EnumSet和EnumMap进行学习。

Java枚举示例

Java enum关键字用于创建枚举类型。
让我们看一下Java枚举示例程序。

package com.theitroad.enums;

public enum ThreadStates {
	START,
	RUNNING,
	WAITING,
	DEAD;
}

在上面的示例中,ThreadStates是具有固定常量字段START,RUNNING,WAITING和DEAD的枚举。

Java枚举与常量

现在,让我们看看Java枚举比Java类中的普通常量字段更好。

让我们在Java中创建一个类似的常量类。

package com.theitroad.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.theitroad.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.theitroad.enum"不是有效的软件包名称。

  • 枚举可以实现接口。
    如上例所示,它实现了" Closeable"界面。

  • 枚举构造函数始终是私有的。

  • 我们无法使用new运算符创建enum实例。

  • 我们可以在Java枚举中声明抽象方法,然后所有枚举字段都必须实现抽象方法。
    在上面的示例中,getDetail()是抽象方法,所有枚举字段均已实现它。

  • 我们可以在枚举中定义一个方法,枚举字段也可以覆盖它们。
    例如,在枚举中定义了" toString()"方法,枚举字段START覆盖了它。

  • Java枚举字段具有命名空间,我们只能将枚举字段用于类名称,例如ThreadStates.START。

  • 枚举可以在switch语句中使用,我们将在本教程的后面部分中看到它的作用。

  • 我们可以扩展现有的枚举而不破坏任何现有的功能。
    例如,我们可以在ThreadStates枚举中添加一个新字段NEW而不影响任何现有功能。

  • 由于枚举字段是常量,因此Java最佳实践是使用大写字母并将其下划线表示空格。
    例如EAST,WEST,EAST_DIRECTION等。

  • 枚举常量是隐式静态的和最终的

  • 枚举常量是最终的,但其变量仍可以更改。
    例如,我们可以使用setPriority()方法来更改枚举常量的优先级。
    我们将在下面的示例中看到它的用法。

  • 由于枚举常量是最终常量,因此我们可以使用" =="和equals()方法安全地比较它们。
    两者将具有相同的结果。

Java EnumSet,EnumMap,valueOf()

现在,我们了解了Enum的大多数功能,让我们看一下Java Enum示例程序。
然后,我们将学习枚举的更多功能。

package com.theitroad.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)方法更改枚举变量的方法。

  • usingUnumValueOf()显示了java.util.Enum valueOf(enumType,name)的用法,通过它我们可以从String创建一个枚举对象。
    如果指定的枚举类型没有带有指定名称的常量,或者指定的类对象不表示枚举类型,则抛出" IllegalArgumentException"。
    如果任何参数为空,它也会抛出" NullPointerException"。

  • " usingEnumValues()"方法显示values()方法的用法,该方法按声明顺序返回包含枚举的所有值的数组。
    请注意,此方法由java编译器自动为每个枚举生成。
    您不会在java.util.Enum类中找到values()实现。

  • usingEnumInSwitch()方法展示了如何在开关情况下使用枚举常量。

  • " usingEnumMap()"方法显示了Java 1.5 Collections Framework中引入的java.util.EnumMap的用法。
    EnumMap是用于枚举类型键的Map实现。
    枚举映射中的所有键都必须来自创建映射时显式或者隐式指定的单个枚举类型。
    我们不能将null用作EnumMap的键,并且EnumMap不同步。

  • " usingEnumSet()"方法显示了java.util.EnumSet的用法,它是用于枚举类型的Set实现。
    枚举集中的所有元素都必须来自创建该枚举集时显式或者隐式指定的单个枚举类型。
    EnumSet不同步,并且不允许使用null元素。
    它还提供了一些有用的方法,例如" copyOf(Collection <E> c)"," of(E首先,E ... rest)"和" complementOf(EnumSet <E> s)"。