Day21 | 枚举(Enum)与常见应用场景

在写代码的时候,经常会遇到一些变量,它们的取值范围是有限且固定的。

例如,一周有七天(周一到周日),订单的几种状态(待支付、处理中、已发货、已完成、已取消),春夏秋冬四个季节。

在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使用教程

如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!

更多文章请关注我的公众号《懒惰蜗牛工坊》

相关推荐
汽车仪器仪表相关领域32 分钟前
PSB-1:安全增压与空燃比双监控仪表 - 高性能引擎的 “双重安全卫士“
java·人工智能·功能测试·单元测试·汽车·可用性测试·安全性测试
c***212934 分钟前
删除文件夹,被提示“需要来自 TrustedInstaller 的权限。。。”的解决方案
java
K***728438 分钟前
springBoot 和springCloud 版本对应关系
spring boot·后端·spring cloud
q***016538 分钟前
Spring 过滤器:OncePerRequestFilter 应用详解
java·后端·spring
z***948438 分钟前
解决SpringBoot项目启动错误:找不到或无法加载主类
java·spring boot·后端
lichong95138 分钟前
android 使用 java 编写网络连通性检查
android·java·前端
TracyCoder12339 分钟前
Java后端Redis客户端选型指南
java·开发语言·redis
u***420741 分钟前
Spring Data JDBC 详解
java·数据库·spring
小周在成长43 分钟前
Java 封装(Encapsulation)指南
后端