枚举(Enum)是 Java 5 引入的一种特殊数据类型,用于定义固定数量的常量集合 (如季节、星期、颜色、状态等),相比传统的 public static final 常量,枚举更安全、可读性更高,且支持面向对象特性(方法、属性、构造器)。
一、枚举的基础定义
1. 最简枚举(无自定义属性 / 方法)
适用于仅需常量标识的场景,语法:enum 枚举名 { 常量1, 常量2, ... }
// 定义星期枚举
public enum Weekday {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
2. 枚举的核心特性
- 枚举类型默认继承
java.lang.Enum(无法手动继承其他类,但可实现接口); - 枚举常量是枚举类的实例 ,默认
public static final; - 枚举类的构造器默认
private(无法外部实例化,保证常量唯一性); - 支持
switch语句(JDK 7+ 也支持 String,但枚举更类型安全)。
二、带属性 / 方法的枚举(进阶)
枚举可像普通类一样定义属性、构造器、方法,适用于常量需要关联额外信息的场景(如状态码 + 描述)。
示例:状态枚举(含编码和描述)
public enum OrderStatus {
// 1. 枚举常量(需放在第一行,参数对应构造器)
PENDING(0, "待付款"),
PAID(1, "已付款"),
SHIPPED(2, "已发货"),
COMPLETED(3, "已完成"),
CANCELLED(4, "已取消");
// 2. 自定义属性
private final int code;
private final String desc;
// 3. 私有构造器(必须private,默认也为private)
OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 4. 普通方法(获取属性)
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
// 5. 静态方法(根据编码查找枚举)
public static OrderStatus getByCode(int code) {
for (OrderStatus status : values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("无效的订单状态码:" + code);
}
// 6. 重写方法(可选)
@Override
public String toString() {
return "OrderStatus{" +
"code=" + code +
", desc='" + desc + '\'' +
'}';
}
}
三、枚举的常用方法
java.lang.Enum 提供了核心方法,所有枚举类默认继承:
| 方法 | 作用 |
|---|---|
values() |
返回枚举常量的数组(按定义顺序),用于遍历枚举 |
valueOf(String) |
根据常量名获取枚举实例(大小写敏感,不存在则抛 IllegalArgumentException) |
ordinal() |
返回枚举常量的索引(从 0 开始,按定义顺序) |
name() |
返回枚举常量的名称(与定义时一致,等同于 toString() 默认实现) |
方法使用示例:
public class EnumTest {
public static void main(String[] args) {
// 1. 遍历所有枚举常量
for (OrderStatus status : OrderStatus.values()) {
System.out.println("名称:" + status.name() +
",索引:" + status.ordinal() +
",描述:" + status.getDesc());
}
// 2. 根据名称获取枚举
OrderStatus paid = OrderStatus.valueOf("PAID");
System.out.println(paid); // 输出重写后的toString
// 3. 自定义方法:根据编码获取枚举
OrderStatus shipped = OrderStatus.getByCode(2);
System.out.println(shipped.getDesc()); // 输出:已发货
// 4. switch语句使用枚举
OrderStatus status = OrderStatus.COMPLETED;
switch (status) {
case PENDING:
System.out.println("请尽快付款");
break;
case COMPLETED:
System.out.println("订单已完成");
break;
default:
System.out.println("订单处理中");
}
}
}
四、枚举的高级用法
1. 枚举实现接口
枚举可实现接口,让不同常量有不同的行为:
public interface Operation {
int calculate(int a, int b);
}
public enum ArithmeticOperation implements Operation {
ADD {
@Override
public int calculate(int a, int b) {
return a + b;
}
},
SUBTRACT {
@Override
public int calculate(int a, int b) {
return a - b;
}
};
}
// 使用
System.out.println(ArithmeticOperation.ADD.calculate(5, 3)); // 8
2. 单例模式(枚举实现)
枚举是实现单例最简洁、安全的方式(天然防反射、序列化):
public enum Singleton {
INSTANCE; // 唯一实例
public void doSomething() {
System.out.println("单例方法执行");
}
}
// 使用
Singleton.INSTANCE.doSomething();
3. 枚举集合(EnumSet/EnumMap)
Java 提供了专门的集合类优化枚举操作,性能优于普通集合:
-
EnumSet:高效存储枚举常量(内部用位运算实现); -
EnumMap:键为枚举的 Map,性能优于 HashMap。// EnumSet示例
EnumSet<Weekday> workDays = EnumSet.range(Weekday.MONDAY, Weekday.FRIDAY);
System.out.println(workDays); // [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]// EnumMap示例
EnumMap<OrderStatus, String> statusMap = new EnumMap<>(OrderStatus.class);
statusMap.put(OrderStatus.PENDING, "待付款订单");
System.out.println(statusMap.get(OrderStatus.PENDING)); // 待付款订单
五、枚举 vs 传统常量
| 特性 | 枚举 | public static final 常量 |
|---|---|---|
| 类型安全 | ✅ 编译期检查,避免传入非法值 | ❌ 本质是 int/String,易传错值 |
| 可读性 | ✅ 语义明确(如 OrderStatus.PAID) | ❌ 需注释说明(如 1 = 已付款) |
| 扩展性 | ✅ 可添加属性 / 方法 | ❌ 仅常量,无扩展能力 |
| 遍历 | ✅ values () 便捷遍历 | ❌ 需手动维护数组 / 集合 |
总结
- 枚举适用于固定且有限的常量集合(状态、类型、选项等);
- 基础场景用最简枚举,需关联信息用带属性的枚举;
- 高级场景可结合接口、单例、EnumSet/EnumMap 提升扩展性和性能;
- 枚举相比传统常量更安全、易维护,是 Java 中常量定义的首选方式。