小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-11 / 2 阅读
0
0

Java枚举详解

Java枚举详解

1. 枚举概述

枚举(Enum)是Java 5引入的一种特殊数据类型,用于定义一组命名的常量。枚举使代码更加清晰、类型安全,并且易于维护。

2. 基本语法

// 最简单的枚举定义
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

// 使用枚举
public class EnumExample {
    public static void main(String[] args) {
        Day today = Day.MONDAY;
        System.out.println("Today is: " + today);
      
        // 遍历所有枚举值
        for (Day day : Day.values()) {
            System.out.println(day);
        }
    }
}

3. 枚举的进阶特性

3.1 带属性和方法的枚举

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;   // 质量(千克)
    private final double radius; // 半径(米)
  
    // 构造函数(默认是private)
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
  
    // 枚举方法
    public double getMass() {
        return mass;
    }
  
    public double getRadius() {
        return radius;
    }
  
    // 计算表面重力
    public double surfaceGravity() {
        final double G = 6.67300E-11; // 重力常数
        return G * mass / (radius * radius);
    }
  
    // 计算物体重量
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
}

3.2 实现接口的枚举

// 定义接口
public interface Operation {
    double apply(double x, double y);
}

// 枚举实现接口
public enum BasicOperation implements 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;
        }
    };
  
    private final String symbol;
  
    BasicOperation(String symbol) {
        this.symbol = symbol;
    }
  
    @Override
    public String toString() {
        return symbol;
    }
}

4. 枚举的常用方法

4.1 内置方法

public class EnumMethods {
    public static void main(String[] args) {
        // values() - 返回所有枚举值
        Day[] days = Day.values();
      
        // valueOf() - 根据名称获取枚举实例
        Day monday = Day.valueOf("MONDAY");
      
        // name() - 返回枚举常量的名称
        String name = Day.MONDAY.name(); // "MONDAY"
      
        // ordinal() - 返回枚举常量的序数(从0开始)
        int ordinal = Day.MONDAY.ordinal(); // 0
      
        // toString() - 返回枚举常量的名称
        String str = Day.MONDAY.toString(); // "MONDAY"
      
        // compareTo() - 比较两个枚举常量的顺序
        int result = Day.MONDAY.compareTo(Day.TUESDAY); // 负数
      
        // equals() - 比较两个枚举常量是否相等
        boolean isEqual = Day.MONDAY.equals(Day.TUESDAY); // false
    }
}

5. 枚举的高级用法

5.1 单例模式

public enum Singleton {
    INSTANCE;
  
    private int value;
  
    public void setValue(int value) {
        this.value = value;
    }
  
    public int getValue() {
        return value;
    }
  
    public void doSomething() {
        System.out.println("Singleton instance: " + value);
    }
}

// 使用单例
public class SingletonDemo {
    public static void main(String[] args) {
        Singleton.INSTANCE.setValue(42);
        Singleton.INSTANCE.doSomething();
    }
}

5.2 策略模式

// 策略枚举
public enum Calculator {
    ADD {
        @Override
        public int calculate(int a, int b) {
            return a + b;
        }
    },
    SUBTRACT {
        @Override
        public int calculate(int a, int b) {
            return a - b;
        }
    },
    MULTIPLY {
        @Override
        public int calculate(int a, int b) {
            return a * b;
        }
    },
    DIVIDE {
        @Override
        public int calculate(int a, int b) {
            if (b == 0) throw new ArithmeticException("Division by zero");
            return a / b;
        }
    };
  
    public abstract int calculate(int a, int b);
}

// 使用策略
public class StrategyDemo {
    public static void main(String[] args) {
        int result = Calculator.ADD.calculate(10, 5); // 15
        System.out.println("Result: " + result);
    }
}

6. 枚举与switch语句

public class EnumSwitch {
    public void describeDay(Day day) {
        switch (day) {
            case MONDAY:
                System.out.println("星期一:开始新的一周");
                break;
            case FRIDAY:
                System.out.println("星期五:周末快到了");
                break;
            case SATURDAY:
            case SUNDAY:
                System.out.println("周末:休息时间");
                break;
            default:
                System.out.println("工作日:努力工作");
        }
    }
  
    public static void main(String[] args) {
        EnumSwitch example = new EnumSwitch();
        example.describeDay(Day.MONDAY);
        example.describeDay(Day.SATURDAY);
    }
}

7. 枚举集合

7.1 EnumSet

import java.util.EnumSet;

public class EnumSetExample {
    public static void main(String[] args) {
        // 创建包含所有元素的EnumSet
        EnumSet<Day> weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
      
        // 创建范围EnumSet
        EnumSet<Day> weekdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
      
        // 创建补集
        EnumSet<Day> allDays = EnumSet.allOf(Day.class);
        EnumSet<Day> notWeekend = EnumSet.complementOf(weekend);
      
        // 遍历
        for (Day day : weekdays) {
            System.out.println(day);
        }
    }
}

7.2 EnumMap

import java.util.EnumMap;

public class EnumMapExample {
    public static void main(String[] args) {
        // 创建EnumMap
        EnumMap<Day, String> activities = new EnumMap<>(Day.class);
      
        // 添加元素
        activities.put(Day.MONDAY, "开会");
        activities.put(Day.TUESDAY, "编码");
        activities.put(Day.WEDNESDAY, "测试");
        activities.put(Day.THURSDAY, "部署");
        activities.put(Day.FRIDAY, "总结");
      
        // 获取值
        String mondayActivity = activities.get(Day.MONDAY);
        System.out.println("周一活动: " + mondayActivity);
      
        // 遍历
        for (Day day : activities.keySet()) {
            System.out.println(day + ": " + activities.get(day));
        }
    }
}

8. 实际应用示例

8.1 状态机

public enum OrderStatus {
    // 订单状态流转
    PENDING {
        @Override
        public OrderStatus next() {
            return CONFIRMED;
        }
    },
    CONFIRMED {
        @Override
        public OrderStatus next() {
            return SHIPPED;
        }
    },
    SHIPPED {
        @Override
        public OrderStatus next() {
            return DELIVERED;
        }
    },
    DELIVERED {
        @Override
        public OrderStatus next() {
            return this; // 最终状态,无法继续流转
        }
    },
    CANCELLED {
        @Override
        public OrderStatus next() {
            return this; // 最终状态,无法继续流转
        }
    };
  
    public abstract OrderStatus next();
  
    public static void main(String[] args) {
        OrderStatus status = OrderStatus.PENDING;
        System.out.println("当前状态: " + status);
      
        status = status.next();
        System.out.println("下一状态: " + status);
    }
}

8.2 错误码枚举

public enum ErrorCode {
    SUCCESS(0, "成功"),
    PARAM_ERROR(1001, "参数错误"),
    USER_NOT_FOUND(1002, "用户不存在"),
    SYSTEM_ERROR(9999, "系统错误");
  
    private final int code;
    private final String message;
  
    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
  
    public int getCode() {
        return code;
    }
  
    public String getMessage() {
        return message;
    }
  
    // 根据code获取枚举
    public static ErrorCode getByCode(int code) {
        for (ErrorCode errorCode : values()) {
            if (errorCode.code == code) {
                return errorCode;
            }
        }
        return SYSTEM_ERROR;
    }
}

9. 最佳实践

  1. 使用枚举代替常量:提高类型安全性和可读性
  2. 合理设计枚举结构:考虑使用属性和方法增强功能
  3. 善用EnumSet和EnumMap:处理枚举集合时性能更好
  4. 考虑使用接口:使枚举更加灵活
  5. 避免使用ordinal():依赖序数会使代码脆弱

总结

Java枚举是一个强大的特性,它不仅提供了类型安全的常量定义,还支持面向对象的编程特性。通过合理使用枚举,可以编写出更加清晰、健壮和易于维护的代码。


评论