Java 枚举的应用场景:从常量到设计模式
1. 替代传统常量类
在枚举出现前,通常用 public static final 定义常量:
public class Status {
public static final int PENDING = 0;
public static final int APPROVED = 1;
public static final int REJECTED = 2;
}
这种方式存在类型不安全、缺少命名空间、打印不直观等问题。
使用枚举后:
public enum Status {
PENDING, APPROVED, REJECTED
}
类型安全:方法签名 setStatus(Status s) 可杜绝非法值传入。
可读性强:Status.PENDING.toString() 直接输出 “PENDING”。
内置方法:values() 遍历所有常量,ordinal() 返回序号,name() 返回名称。
支持 switch:可直接配合 switch-case 使用。
进阶用法可为常量关联字段:
public enum ErrorCode {
SUCCESS(200, “成功”),
NOT_FOUND(404, “未找到”),
ERROR(500, “服务器内部错误”);
private final int code;
private final String msg;
ErrorCode(int code, String msg) { this.code = code; this.msg = msg; }
public int getCode() { return code; }
public String getMsg() { return msg; }
}
2. 实现单例模式
利用枚举天生线程安全、防反射和防序列化破坏的特性,可写出最简洁的单例。
public enum Singleton {
INSTANCE;
public void doSomething() { … }
}
调用:Singleton.INSTANCE.doSomething();
《Effective Java》推荐这种方式:枚举单例不会被反射实例化(Constructor.newInstance() 会抛出异常),反序列化也不会创建新实例,是目前最安全的单例实现。
3. 策略模式
定义抽象方法,每个枚举常量分别实现,即可形成策略模式。
public enum PaymentMethod {
WECHAT {
@Override
public void pay(double amount) {
System.out.println(“微信支付:” + amount + “ 元”);
}
},
ALIPAY {
@Override
public void pay(double amount) {
System.out.println(“支付宝支付:” + amount + “ 元”);
}
};
public abstract void pay(double amount);
}
使用时直接:
PaymentMethod method = PaymentMethod.WECHAT;
method.pay(100.00);
新增一种支付方式只需添加一个枚举常量并实现抽象方法,无需修改已有代码,符合开闭原则。
4. 状态机
通过抽象方法定义状态转换规则,可清晰表达有限状态机。
public enum OrderState {
PENDING {
@Override public OrderState next() { return CONFIRMED; }
},
CONFIRMED {
@Override public OrderState next() { return SHIPPED; }
},
SHIPPED {
@Override public OrderState next() { return DELIVERED; }
},
DELIVERED {
@Override public OrderState next() { return this; }
};
public abstract OrderState next();
}
结合字段还能记录触发事件、附加数据等,使状态流转逻辑集中在枚举内,减少分散的 if-else。
5. EnumSet 与 EnumMap
Java 为枚举专门提供了高效集合:
EnumSet
EnumMap<Status, String> map = new EnumMap<>(Status.class);
map.put(Status.PENDING, “待处理”);
EnumSet:以位向量实现,空间、时间效率极高,适用于标志位、枚举集合等场景。
EnumMap:以数组为底,键不重复,顺序为枚举定义顺序,性能优于普通 HashMap。
总结与建议
何时用枚举:固定常量集、状态机、单例、策略模式等。
注意:枚举初始化在静态块之前,构造器中避免依赖其他静态资源;枚举默认实现 Serializable 且序列化安全。
不要滥用:如果策略逻辑过于复杂或数量庞大,建议单独使用策略类,枚举仅作为工厂或选择器。
掌握枚举的这些用法,能让你的代码更简洁、安全、易于维护。
