在写代码的时候,经常会遇到一些变量,它们的取值范围是有限且固定的。
例如,一周有七天(周一到周日),订单的几种状态(待支付、处理中、已发货、已完成、已取消),春夏秋冬四个季节。
在Java 5之前,我们一般使用public static final修饰常量来表示这些值,但这种方式存在很多弊端。
今天,我们一起探讨Java提供的一种更强大、更安全的解决方案------枚举(Enum)。
一、没有枚举之前
在枚举出现之前,我们通常这样定义一组相关的常量:
java
package com.lazy.snail.day21;
/**
* @ClassName ConstantsDemo
* @Description TODO
* @Author lazysnail
* @Date 2025/6/6 13:46
* @Version 1.0
*/
public class ConstantsDemo {
public static final int STATUS_PENDING = 1;
public static final int STATUS_PROCESSING = 2;
public static final int STATUS_SHIPPED = 3;
public static final int STATUS_COMPLETED = 4;
public void processOrderStatus(int status) {
if (ConstantsDemo.STATUS_COMPLETED == status) {
System.out.println("订单处理完成");
} else if (ConstantsDemo.STATUS_PROCESSING == status) {
System.out.println("订单处理中");
}
// ...
}
}
这样的写法可能会引发一些问题。
假如方法的调用者传入了一些没有定义的常量值,可能会导致程序逻辑出问题。
这些常量一般都分散在各个类里,如果多了,很可能就产生命名冲突。
如果你在调试的时候,只能输出数字,而不是有意义的名称,比如PENDING、PROCESSING。
没办法遍历所有可能得值。
如果你使用了switch,switch语句没办法检查你是不是覆盖了所有可能的值。
就是因为这些问题,Java 5正式引入了enum关键字。
二、枚举的基本用法(常量)
枚举是一种特殊的类,它允许我们定义一个由固定的、命名的常量组成集合的类型。
1、基本定义
定义一个枚举其实很简单:
java
package com.lazy.snail.day21;
/**
* @ClassName DayOfWeek
* @Description TODO
* @Author lazysnail
* @Date 2025/6/6 13:57
* @Version 1.0
*/
public enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
DayOfWeek就是一个枚举类型,MONDAY、TUESDAY等是这个类型的实例(就是DayOfWeek类型的对象)。
2、基本使用
java
package com.lazy.snail.day21;
/**
* @ClassName EnumDemo
* @Description TODO
* @Author lazysnail
* @Date 2025/6/6 14:00
* @Version 1.0
*/
public class EnumDemo {
public static void main(String[] args) {
DayOfWeek today = DayOfWeek.FRIDAY;
switch (today) {
case MONDAY -> System.out.println("又要开始搬砖了");
case FRIDAY -> System.out.println("搬砖结束");
case SATURDAY -> System.out.println("享受周末");
default -> System.out.println("一天又一天");
}
System.out.println(today);
}
}
方法只接受指定类型的实例,避免传入无效值。
代码里能够直观的看出常量的含义。
三、特殊类
在Java中,每个enum类型都是java.lang.Enum类的隐式子类,并且它本身是一个final类,不能被其他类继承。
这意味着枚举可以拥有自己的字段(成员变量)、方法、构造函数、实现接口。
1、给枚举添加字段、方法和构造函数
我们可以为每个枚举实例关联额外的数据和行为。
java
package com.lazy.snail.day21;
/**
* @ClassName OrderStatus
* @Description TODO
* @Author lazysnail
* @Date 2025/6/6 14:12
* @Version 1.0
*/
public enum OrderStatus {
PENDING(10, "待支付"),
PROCESSING(20, "处理中"),
SHIPPED(30, "已发货"),
COMPLETED(40, "已完成"),
CANCELED(50, "已取消");
private final int code;
private final String description;
OrderStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static void main(String[] args) {
OrderStatus status = OrderStatus.COMPLETED;
System.out.println("订单状态:" + status);
System.out.println("状态编码:" + status.getCode());
System.out.println("状态描述:" + status.getDescription());
}
}
上面定义的枚举类中,有私有字段、构造函数和公共方法。
2、枚举的内置方法
java.lang.Enum基类为所有枚举提供了几个有用的静态和实例方法:
values()
java
for (OrderStatus s : OrderStatus.values()) {
System.out.printf("编码: %d, 描述: %s\n", s.getCode(), s.getDescription());
}
values()方法是一个静态方法,返回一个包含所有枚举实例的数组。
使用这个方法,配合for循环,可以方便的对所有枚举常量进行遍历。
valueOf(String name)
java
OrderStatus status1 = OrderStatus.valueOf("COMPLETED");
valueOf(String name)也是一个静态方法,可以根据给定的字符串名称返回对应的枚举实例。
如果名称不匹配,就会抛出异常(IllegalArgumentException)。
name()
这是一个实例方法,返回枚举实例的名称(即声明时的标识符,比如"COMPLETED")。
ordinal()
这是一个实例方法,返回枚举实例在声明时的序数(从0开始)。
这个方法一般都不会在业务代码里使用。、 万一你在枚举声明里改变了常量的顺序,所有依赖ordinal()的代码都会出错。
四、常见的应用场景
上面提到过的常量这些简单的应用就不说了。
状态机
枚举非常适合用来表示有限状态机的状态。
每个枚举实例代表一个状态,并且可以在枚举类中定义方法来处理状态转换逻辑。
java
public enum TrafficLight {
RED {
public TrafficLight next() { return GREEN; }
},
GREEN {
public TrafficLight next() { return YELLOW; }
},
YELLOW {
public TrafficLight next() { return RED; }
};
public abstract TrafficLight next();
}
TrafficLight light = TrafficLight.RED;
System.out.println("Current light: " + light);
light = light.next();
System.out.println("Next light: " + light);
light = light.next();
System.out.println("Next light: " + light);
上面这个红绿灯的案例,每种状态中还定义了方法,来实现红绿灯状态的转换。
EnumSet和EnumMap
Java的集合框架还给枚举提供了两个高度优化的实现。
EnumSet
这是一个专门为枚举类设计的Set实现。
它的内部使用位向量实现,性能上来说比HashSet好很多。

EnumMap
这是一个键为枚举类型的Map实现。
它的内部使用数组实现,性能也优于HashMap。

结语
今天就简单的介绍了一下枚举类。
列举了一些简单的用法和实际开发场景中的用途。
案例中的Java集合框架将在接下来的文章中逐一进行介绍。
下一篇预告
Day22 | IDEA使用教程
如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!
更多文章请关注我的公众号《懒惰蜗牛工坊》