← 返回首页
📋

Java枚举详解:定义、使用与高级特性

📂 java ⏱ 5 min 890 words

Java枚举详解:定义、使用与高级特性

概述

枚举(Enum)是Java 5引入的特殊数据类型,用于定义固定常量集合。枚举比常量类更安全、更简洁,支持方法、字段和构造方法。

1. 基本枚举

// 定义枚举
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

// 使用枚举
public class EnumBasicExample {
    public static void main(String[] args) {
        Season season = Season.SPRING;
        
        // 比较枚举
        if (season == Season.SPRING) {
            System.out.println("现在是春天");
        }
        
        // 遍历枚举
        System.out.println("所有季节:");
        for (Season s : Season.values()) {
            System.out.println("- " + s);
        }
        
        // 获取枚举常量
        Season spring = Season.valueOf("SPRING");
        System.out.println("Spring: " + spring);
        
        // 获取枚举索引
        System.out.println("SPRING索引: " + Season.SPRING.ordinal());
        System.out.println("SUMMER索引: " + Season.SUMMER.ordinal());
    }
}

2. 带字段和方法的枚举

public 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;    // 质量(kg)
    private final double radius;  // 半径(m)
    
    // 构造方法(默认private)
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    
    // 方法
    public double surfaceGravity() {
        final double G = 6.67300E-11;
        return G * mass / (radius * radius);
    }
    
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    
    // Getter方法
    public double getMass() {
        return mass;
    }
    
    public double getRadius() {
        return radius;
    }
}

// 使用带字段的枚举
public class PlanetExample {
    public static void main(String[] args) {
        double earthWeight = 75.0;  // 地球上的体重(kg)
        double mass = earthWeight / Planet.EARTH.surfaceGravity();
        
        for (Planet p : Planet.values()) {
            System.out.printf("%s上的体重: %7.2f N%n",
                p, p.surfaceWeight(mass));
        }
    }
}

3. 枚举实现接口

public interface Printable {
    void print();
}

public enum Color implements Printable {
    RED("红色", 255, 0, 0),
    GREEN("绿色", 0, 255, 0),
    BLUE("蓝色", 0, 0, 255),
    YELLOW("黄色", 255, 255, 0);
    
    private final String name;
    private final int r, g, b;
    
    Color(String name, int r, int g, int b) {
        this.name = name;
        this.r = r;
        this.g = g;
        this.b = b;
    }
    
    @Override
    public void print() {
        System.out.println("颜色: " + name + ", RGB(" + r + ", " + g + ", " + b + ")");
    }
    
    public String getName() {
        return name;
    }
    
    public int getR() {
        return r;
    }
    
    public int getG() {
        return g;
    }
    
    public int getB() {
        return b;
    }
    
    // 根据名称查找枚举
    public static Color fromName(String name) {
        for (Color color : values()) {
            if (color.name.equals(name)) {
                return color;
            }
        }
        throw new IllegalArgumentException("未知颜色: " + name);
    }
    
    public static void main(String[] args) {
        for (Color color : Color.values()) {
            color.print();
        }
        
        Color red = Color.fromName("红色");
        System.out.println("查找到的颜色: " + red.getName());
    }
}

4. 抽象方法枚举

public enum Operation {
    ADD("+") {
        @Override
        public double apply(double x, double y) {
            return x + y;
        }
    },
    SUBTRACT("-") {
        @Override
        public double apply(double x, double y) {
            return x - y;
        }
    },
    MULTIPLY("*") {
        @Override
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) {
            if (y == 0) {
                throw new ArithmeticException("除数不能为0");
            }
            return x / y;
        }
    };
    
    private final String symbol;
    
    Operation(String symbol) {
        this.symbol = symbol;
    }
    
    public abstract double apply(double x, double y);
    
    @Override
    public String toString() {
        return symbol;
    }
    
    public static void main(String[] args) {
        double x = 10;
        double y = 5;
        
        for (Operation op : Operation.values()) {
            System.out.printf("%.1f %s %.1f = %.1f%n", x, op, y, op.apply(x, y));
        }
    }
}

5. 枚举与Switch

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

public class EnumSwitchExample {
    public static String getDayType(Day day) {
        return switch (day) {
            case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "工作日";
            case SATURDAY, SUNDAY -> "周末";
        };
    }
    
    public static void main(String[] args) {
        for (Day day : Day.values()) {
            System.out.println(day + ": " + getDayType(day));
        }
    }
}

6. 枚举集合

import java.util.EnumMap;
import java.util.EnumSet;

public class EnumCollectionExample {
    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    public static void main(String[] args) {
        // EnumSet
        EnumSet<Day> weekdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
        EnumSet<Day> weekend = EnumSet.complementOf(weekdays);
        
        System.out.println("工作日: " + weekdays);
        System.out.println("周末: " + weekend);
        
        // EnumMap
        EnumMap<Day, String> dayActivities = new EnumMap<>(Day.class);
        dayActivities.put(Day.MONDAY, "开会");
        dayActivities.put(Day.TUESDAY, "编码");
        dayActivities.put(Day.WEDNESDAY, "测试");
        dayActivities.put(Day.THURSDAY, "评审");
        dayActivities.put(Day.FRIDAY, "部署");
        dayActivities.put(Day.SATURDAY, "休息");
        dayActivities.put(Day.SUNDAY, "学习");
        
        System.out.println("每日活动:");
        dayActivities.forEach((day, activity) ->
            System.out.println(day + ": " + activity));
    }
}

7. 实际应用示例

订单状态管理

public enum OrderStatus {
    CREATED("已创建", true),
    PAID("已支付", true),
    SHIPPED("已发货", true),
    DELIVERED("已送达", false),
    CANCELLED("已取消", false);
    
    private final String description;
    private final boolean active;
    
    OrderStatus(String description, boolean active) {
        this.description = description;
        this.active = active;
    }
    
    public String getDescription() {
        return description;
    }
    
    public boolean isActive() {
        return active;
    }
    
    public boolean canTransitionTo(OrderStatus newStatus) {
        return switch (this) {
            case CREATED -> newStatus == PAID || newStatus == CANCELLED;
            case PAID -> newStatus == SHIPPED || newStatus == CANCELLED;
            case SHIPPED -> newStatus == DELIVERED;
            case DELIVERED -> false;
            case CANCELLED -> false;
        };
    }
    
    public static OrderStatus fromString(String status) {
        for (OrderStatus orderStatus : values()) {
            if (orderStatus.name().equalsIgnoreCase(status)) {
                return orderStatus;
            }
        }
        throw new IllegalArgumentException("未知状态: " + status);
    }
}

// 使用枚举管理订单状态
public class Order {
    private String orderId;
    private OrderStatus status;
    
    public Order(String orderId) {
        this.orderId = orderId;
        this.status = OrderStatus.CREATED;
    }
    
    public void transitionTo(OrderStatus newStatus) {
        if (status.canTransitionTo(newStatus)) {
            this.status = newStatus;
            System.out.println("订单 " + orderId + " 状态变更: " + newStatus.getDescription());
        } else {
            System.out.println("无法从 " + status + " 转换到 " + newStatus);
        }
    }
    
    public void display() {
        System.out.println("订单 " + orderId + " 当前状态: " + status.getDescription());
    }
    
    public static void main(String[] args) {
        Order order = new Order("ORD001");
        
        order.display();
        order.transitionTo(OrderStatus.PAID);
        order.display();
        
        order.transitionTo(OrderStatus.SHIPPED);
        order.display();
        
        order.transitionTo(OrderStatus.DELIVERED);
        order.display();
        
        // 尝试无效转换
        order.transitionTo(OrderStatus.CANCELLED);
    }
}

8. 最佳实践

  1. 使用枚举代替常量类:枚举更安全、更简洁
  2. 为枚举添加字段和方法:让枚举携带更多信息
  3. 使用EnumSet和EnumMap:提高枚举集合的性能
  4. 使用switch处理枚举:清晰地处理不同枚举值
  5. 文档化枚举值:清楚地文档化每个枚举值的含义

总结

枚举是Java中强大的特性,它提供了类型安全的常量定义方式。通过枚举,可以定义固定常量集合、添加字段和方法、实现接口等。掌握枚举的使用,可以编写更安全、更可维护的Java代码。