ZetCode

Java 枚举类

最后修改时间:2025 年 4 月 13 日

java.lang.Enum 类是所有 Java 枚举类型的公共基类。 枚举提供了一种定义一组命名常量的方法,从而确保类型安全并提高代码的可读性和可维护性。 它们消除了使用 static final 变量进行传统常量定义的需求,从而防止分配无效值。

与常规类一样,Java 中的枚举可以包含字段、方法和构造函数,但它们主要用于表示具有内置类型安全性的固定常量集。 它们可以实现接口,从而允许额外的行为定制,但不能扩展其他类,因为它们隐式扩展 java.lang.Enum。 这使得枚举成为表示相关常量的固定集合的理想选择,例如星期几、错误代码或配置选项。

枚举类方法

Enum 类提供了几种实用方法,可帮助管理枚举实例并与之交互。 一些关键方法包括:

通过利用枚举,开发人员可以创建结构化的、自我记录的代码,同时通过强制值约束来确保正确性。

基本枚举声明

枚举声明的最简单形式是定义一组命名常量。 每个常量都是枚举类型的一个实例。 枚举是隐式 public、static 和 final 的。 它们可以在 switch 语句中使用,并提供编译时类型安全。

Main.java
enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY
}

void main() {

    Day today = Day.WEDNESDAY;
    
    System.out.println("Today is: " + today);
    System.out.println("Ordinal value: " + today.ordinal());
    System.out.println("Name: " + today.name());
    
    // Using enum in switch statement
    switch (today) {
        case MONDAY:
            System.out.println("Start of work week");
            break;
        case WEDNESDAY:
            System.out.println("Midweek");
            break;
        case FRIDAY:
            System.out.println("Almost weekend");
            break;
        default:
            System.out.println("Other day");
    }
}

此示例演示了基本的枚举声明和用法。 Day 枚举定义了七个常量,代表一周中的几天。 我们展示了如何访问枚举常量、其序数值和名称。 该示例还演示了如何在 switch 语句中使用枚举。

带字段和方法的枚举

与常规类一样,枚举可以具有字段、方法和构造函数。 每个枚举常量都可以具有其自己的特定于实例的行为。 枚举构造函数必须是 private 或 package-private,因为枚举常量只能在枚举本身中创建。

Main.java
enum Planet {

    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6),
    JUPITER(1.9e+27, 7.1492e7),
    SATURN(5.688e+26, 6.0268e7),
    URANUS(8.686e+25, 2.5559e7),
    NEPTUNE(1.024e+26, 2.4746e7);
    
    private final double mass;   // in kilograms
    private final double radius; // in meters
    
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    
    public double surfaceGravity() {
        double G = 6.67300E-11;
        return G * mass / (radius * radius);
    }
    
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
}

void main() {

    double earthWeight = 70; // kg
    double mass = earthWeight / Planet.EARTH.surfaceGravity();
    
    for (Planet p : Planet.values()) {
        System.out.printf("Your weight on %s is %f kg%n",
                         p, p.surfaceWeight(mass));
    }
}

此示例显示了带有字段和方法的枚举。 Planet 枚举表示我们太阳系中的行星,具有质量和半径属性。 每个行星常量都提供计算表面重力和重量的方法。 该示例计算并打印了一个人在每个行星上的重量。

带抽象方法的枚举

枚举可以声明必须由每个枚举常量实现的抽象方法。 这允许每个常量定义其自身的行为,同时共享通用的枚举功能。 这种模式称为特定于常量的方法实现。

Main.java
enum Operation {

    PLUS {
        public double apply(double x, double y) { return x + y; }
    },
    MINUS {
        public double apply(double x, double y) { return x - y; }
    },
    TIMES {
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE {
        public double apply(double x, double y) { return x / y; }
    };
    
    public abstract double apply(double x, double y);
}

void main() {

    double x = 10;
    double y = 5;
    
    for (Operation op : Operation.values()) {
        System.out.printf("%s %s %s = %s%n",
                        x, op, y, op.apply(x, y));
    }
}

此示例演示了带有抽象方法的枚举。 Operation 枚举定义了四个基本算术运算。 每个常量都使用其特定行为实现 apply 方法。 该示例展示了如何迭代所有操作并将它们应用于示例值。

实现接口的枚举

与常规类一样,枚举可以实现接口。 这允许枚举提供多态行为,同时保持其类型安全性和固定的实例集。 每个枚举常量可以以不同的方式实现接口方法。

Main.java
interface Command {
    void execute();
}

enum FileOperation implements Command {
    OPEN {
        public void execute() {
            System.out.println("Opening file...");
        }
    },
    SAVE {
        public void execute() {
            System.out.println("Saving file...");
        }
    },
    CLOSE {
        public void execute() {
            System.out.println("Closing file...");
        }
    };
}

void main() {

    Command[] operations = FileOperation.values();
    
    for (Command cmd : operations) {
        cmd.execute();
    }
}

此示例显示了一个实现接口的枚举。 FileOperation 枚举实现了 Command 接口,每个常量都提供其自身的 execute 方法实现。 该示例演示了如何通过接口以多态方式处理枚举常量。

带有静态工厂方法的枚举

枚举可以具有静态工厂方法,这些方法根据特定标准返回枚举常量。 当您需要按名称以外的属性查找枚举常量时,这非常有用。 默认情况下提供的 valueOf 方法仅按名称查找。

Main.java
enum HttpStatus {

    OK(200, "OK"),
    NOT_FOUND(404, "Not Found"),
    SERVER_ERROR(500, "Internal Server Error");
    
    private final int code;
    private final String description;
    
    HttpStatus(int code, String description) {
        this.code = code;
        this.description = description;
    }
    
    public int getCode() { return code; }
    public String getDescription() { return description; }
    
    public static HttpStatus fromCode(int code) {
        for (HttpStatus status : values()) {
            if (status.code == code) {
                return status;
            }
        }
        throw new IllegalArgumentException("No status for code: " + code);
    }
}

void main() {

    HttpStatus status = HttpStatus.fromCode(404);
    System.out.println(status + ": " + status.getDescription());
    
    try {
        HttpStatus.fromCode(999);
    } catch (IllegalArgumentException e) {
        System.out.println("Error: " + e.getMessage());
    }
}

此示例演示了带有静态工厂方法的枚举。 HttpStatus 枚举表示带有其描述的 HTTP 状态代码。 fromCode 方法按其数字代码查找状态。 该示例显示了成功的查找和错误处理。

具有状态和行为的枚举

枚举可以维护状态并实现复杂的行为。 它们可用于实现状态机或其他需要具有特定行为的固定实例集的模式。 此示例显示了一个简单的自动售货机状态。

Main.java
enum VendingMachineState {

    IDLE {
        public VendingMachineState nextState() {
            return WAITING_FOR_MONEY;
        }
    },
    WAITING_FOR_MONEY {
        public VendingMachineState nextState() {
            return DISPENSING;
        }
    },
    DISPENSING {
        public VendingMachineState nextState() {
            return IDLE;
        }
    },
    OUT_OF_STOCK {
        public VendingMachineState nextState() {
            return this;
        }
    };
    
    public abstract VendingMachineState nextState();
}

void main() {

    VendingMachineState state = VendingMachineState.IDLE;
    
    System.out.println("Initial state: " + state);
    
    state = state.nextState();
    System.out.println("After first transition: " + state);
    
    state = state.nextState();
    System.out.println("After second transition: " + state);
    
    state = state.nextState();
    System.out.println("After third transition: " + state);
    
    state = VendingMachineState.OUT_OF_STOCK;
    System.out.println("Out of stock state remains: " + 
                      state.nextState());
}

此示例显示了一个实现简单状态机的枚举。 VendingMachineState 枚举表示自动售货机的不同状态。 每个状态都通过 nextState 方法知道其下一个状态。 该示例演示了状态转换和 OUT_OF_STOCK 的特殊情况,它不会转换。

来源

Java 枚举类文档

在本文中,我们通过实际示例介绍了 Java Enum 类的所有主要方面。 枚举是强大的构造,超越了简单的常量,提供了类型安全、封装和多态行为。

作者

我叫 Jan Bodnar,是一位敬业的程序员,在该领域拥有多年的经验。 我于 2007 年开始撰写编程文章,此后撰写了超过 1,400 篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程