枚举类型

使用枚举类型,可以取代前面学习过的定义常量的方式,同时枚举类型还赋予程序在编译时进行检查的功能。本节将详细讲解枚举类型。

使用枚举类型设置常量

设置常量时,我们通常将常量放置在接口中,这样在程序中就可以直接对其进行使用。该常量不能被修改,因为在接口中定义常量时,该常量的修饰符为 final 与 static。常规定义常量的代码如下:

public interface Constants {
    public static final int Constants_A = 1;
    public static final int Constants_B = 12;
}

枚举类型出现后,逐渐取代了上述常量定义方式。使用枚举类型定义常量的语法如下:

public enum Constants {
    Constants_A,
    Constants_B,
}

其中,enum 是定义枚举类型的关键字。当需要在程序中使用该常量时,可以使用 Constants.Constants_A 来表示。

【例13.1】分别创建四季的接口常量和枚举,比较二者的使用场景(实例位置:资源包\TM\sl\13\1)

分别创建 SeasonInterface 接口和 SeasonEnum 枚举来定义四季常量,在 SeasonDemo 类中创建两个 printSeason() 方法,分别以 SeasonInterface 接口常量和 SeasonEnum 枚举作为参数,输出传入的月份名称。尝试在调用 printSeason() 方法时使用接口常量值以外的数字 “冒充” 常量值。

interface SeasonInterface {							// 四季接口
	int SPRING = 1, SUMMER = 2, AUTUMN = 3, WINTER = 4;
}

enum SeasonEnum {								// 四季枚举
	SPRING, SUMMER, AUTUMN, WINTER
}

public class SeasonDemo {

	public static void printSeason1(int season) {
		switch (season) {
		case SeasonInterface.SPRING:
			System.out.println("这是春季");break;
		case SeasonInterface.SUMMER:
			System.out.println("这是夏季");break;
		case SeasonInterface.AUTUMN:
			System.out.println("这是秋季");break;
		case SeasonInterface.WINTER:
			System.out.println("这是冬季");break;
		default:
			System.out.println("这不是四季的常量值");
		}
	}
	
	public static void printSeason2(SeasonEnum season) {
		switch (season) {
		case SPRING:
			System.out.println("这是春季");break;
		case SUMMER:
			System.out.println("这是夏季");break;
		case AUTUMN:
			System.out.println("这是秋季");break;
		case WINTER:
			System.out.println("这是冬季");break;
		}
	}

	public static void main(String[] args) {
		printSeason1(SeasonInterface.SPRING);	// 使用接口常量做参数
		printSeason1(3);						// 可以使用数字做出参数
		printSeason1(-1);					// 也使用接口常量值以外的数字“冒充”常量
		printSeason2(SeasonEnum.WINTER); 	// 使用枚举做参数,只能用枚举有中的值,无法“冒充”
	}
}

运行结果如下:

     这是春季
     这是秋季
     这不是四季的常量值
     这是冬季

深入了解枚举类型

枚举类型较传统定义常量的方式,除具有参数类型检测的优势外,还具有其他方面的优势。

用户可以将一个枚举类型看作是一个类,它继承自 java.lang.Enum 类,当定义一个枚举类型时,每一个枚举类型成员都可以被看作是枚举类型的一个实例,这些枚举类型成员都默认被 final、public、static 修饰,因此当使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。

由于枚举类型对象继承自 java.lang.Enum 类,因此该类中一些操作枚举类型的方法都可以应用到枚举类型中。表13.1中列举了枚举类型中的常用方法。

image 2024 03 05 11 24 44 021
Figure 1. 表13.1 枚举类型的常用方法

接下来,具体讲解枚举类型的常用方法与构造方法。

values()方法

枚举类型实例包含一个 values() 方法,该方法将枚举中所有的枚举值以数组的形式返回。

【例13.2】输出四季枚举中的所有枚举值(实例位置:资源包\TM\sl\13\2)

在项目中创建 ShowEnum 类,在该类中使用枚举类型中的 values() 方法获取四季枚举中的所有枚举值并进行输出。

enum SeasonEnum { // 四季枚举
	SPRING, SUMMER, AUTUMN, WINTER
}

public class ShowEnum {
	public static void main(String[] args) {
		SeasonEnum es[] = SeasonEnum.values();
		for (int i = 0; i < es.length; i++) {
			System.out.println("枚举常量:" + es[i]);
		}
	}
}

运行结果如下:

     枚举常量:SPRING
     枚举常量:SUMMER
     枚举常量:AUTUMN
     枚举常量:WINTER

valueOf()方法与compareTo()方法

枚举类型中静态方法 valueOf() 可以将普通字符串转换为枚举类型,而 compareTo() 方法用于比较两个枚举类型对象定义时的顺序。

【例13.3】使用字符串创建一个季节的枚举值,并判断季节的位置(实例位置:资源包\TM\sl\13\3)

创建 EnumMethodTest 类,在主方法中创建字面值为 “SUMMER” 的季节枚举,将创建出的枚举与四季枚举的每一个值进行对比,以判断 “SUMMER” 所在的位置。

enum SeasonEnum { // 四季枚举
	SPRING, SUMMER, AUTUMN, WINTER
}

public class EnumMethodTest {
	public static void main(String[] args) {
		SeasonEnum tmp = SeasonEnum.valueOf("SUMMER");// 根据字符串创建一个枚举值
		SeasonEnum es[] = SeasonEnum.values();// 获取所有枚举值
		for (int i = 0; i < es.length; i++) {
			String message = "";// 待输出的消息
			int result = tmp.compareTo(es[i]);// 记录两个枚举的比较结果
			if (result < 0) {
				message = tmp + "在" + es[i] + "的前个" + (-result) + "位置";
			} else if (result > 0) {
				message = tmp + "与" + es[i] + "的后个" + result + "位置";
			} else if (result == 0) {
				message = tmp + "与" + es[i] + "是同一个值";
			}
			System.out.println(message);
		}
	}
}

运行结果如下:

     SUMMER在SPRING的后1个位置
     SUMMER与SUMMER是同一个值
     SUMMER在AUTUMN的前1个位置
     SUMMER在WINTER的前2个位置

ordinal()方法

枚举类型中的 ordinal() 方法用于获取某个枚举对象的位置索引值。

【例13.4】输出每一个季节的索引位置(实例位置:资源包\TM\sl\13\4)

在项目中创建 EnumIndexTest 类,在该类中使用枚举类型中的 ordinal() 方法获取枚举类型成员的位置索引。

enum SeasonEnum { // 四季枚举
	SPRING, SUMMER, AUTUMN, WINTER
}

public class EnumIndexTest {
	public static void main(String[] args) {
		SeasonEnum es[] = SeasonEnum.values();
		for (int i = 0; i < es.length; i++) {
			System.out.println(es[i] + "在枚举类型中位置索引值" + es[i].ordinal());
		}
	}
}

运行结果如下:

     SPRING在枚举类型中位置索引值0
     SUMMER在枚举类型中位置索引值1
     AUTUMN在枚举类型中位置索引值2
     WINTER在枚举类型中位置索引值3

枚举类型中的构造方法

在枚举类型中,可以添加构造方法,但是规定这个构造方法必须由private修饰符修饰。枚举类型定义的构造方法语法如下:

enum 枚举类型名称 {
  Constants_A("我是枚举成员A"),
  Constants_B("我是枚举成员B"),
  Constants_C("我是枚举成员C"),
  Constants_D(3);
  private String description;
  private Constants2() { // 定义默认构造方法
  }
  private Constants2(String description) { // 定义带参数的构造方法,参数类型为字符串型
    this.description = description;
  }
  private Constants2(int i) { // 定义带参数的构造方法,参数类型为整型
    this.i = this.i + i;
  }
}

从枚举类型构造方法的语法中可以看出,无论是无参构造方法还是有参构造方法,修饰权限都为 private。定义一个有参构造方法后,需要对枚举类型成员相应地使用该构造方法,如 Constants_A("我是枚举成员A") 和 Constants_D(3) 语句,相应地使用了参数为 String 型和参数为 int 型的构造方法。然后可以在枚举类型中定义两个成员变量,在构造方法中为这两个成员变量赋值,这样就可以在枚举类型中定义该成员变量的 getXXX() 方法了。

【例13.5】为四季枚举创建构造方法,记录每一个季节的特征(实例位置:资源包\TM\sl\13\5)

在四季枚举中创建一个字符串类型的备注属性,并创建该属性的 Getter 方法,在枚举构造方法中为备注属性赋值,最后输出每一个季节枚举的备注值。

enum SeasonEnum { // 四季枚举
	SPRING("万物复苏"), SUMMER("烈日炎炎"), AUTUMN("秋草枯黄"), WINTER("白雪皑皑");

	private String remarks;// 枚举的备注

	private SeasonEnum(String remarks) {// 构造方法
		this.remarks = "我是" + this.toString() + ",我来之后" + remarks + "。";
	}

	public String getRemarks() {// 获取备注值
		return remarks;
	}
}

public class EnumIConstructTest {
	public static void main(String[] args) {
		SeasonEnum es[] = SeasonEnum.values();
		for (int i = 0; i < es.length; i++) {
			System.out.println(es[i].getRemarks());
		}
	}
}

运行结果如下:

     我是SPRING,我来之后万物复苏。
     我是SUMMER,我来之后烈日炎炎。
     我是AUTUMN,我来之后秋草枯黄。
     我是WINTER,我来之后白雪皑皑。

使用枚举类型的优势

枚举类型声明提供了一种对用户友好的变量定义方法,枚举了某种数据类型所有可能出现的值。总结枚举类型,它具有以下特点:

  • 类型安全。

  • 紧凑有效的数据定义。

  • 可以和程序其他部分完美交互。

  • 运行效率高。

编程训练(答案位置:资源包\TM\sl\13\编程训练)

【训练1】月份枚举 创建月份枚举,共12个月。

【训练2】星期枚举 在控制台中输入要查询的英文星期简写(小写,如 mon)后,控制台输出该星期简称的中英文对照(例如:MONDAY—星期一)。