Java枚举详解:定义、使用与高级特性
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. 最佳实践
- 使用枚举代替常量类:枚举更安全、更简洁
- 为枚举添加字段和方法:让枚举携带更多信息
- 使用EnumSet和EnumMap:提高枚举集合的性能
- 使用switch处理枚举:清晰地处理不同枚举值
- 文档化枚举值:清楚地文档化每个枚举值的含义
总结
枚举是Java中强大的特性,它提供了类型安全的常量定义方式。通过枚举,可以定义固定常量集合、添加字段和方法、实现接口等。掌握枚举的使用,可以编写更安全、更可维护的Java代码。