Java 枚举是 JDK 5 引入的一种特殊类型,本质上是一个类,可以包含构造方法、成员变量和方法。枚举不仅提供了类型安全的常量定义方式,还能承载更丰富的业务逻辑。
一、基本概念
Java 枚举(Enumeration)是 JDK 5 引入的一种特殊类型,它本质上是一个类,可以包含构造方法、成员变量和方法。枚举不仅提供了类型安全的常量定义方式,还能承载更丰富的业务逻辑。
与传统的 public static final 常量相比,枚举提供了:
- 类型安全:编译时检查,避免错误的常量赋值
- 代码可读性:自文档化的常量定义
- 扩展性:可以添加方法、构造函数和成员变量
二、最简单的枚举定义
2.1 基本语法
// 定义季节枚举
enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER
}
2.2 使用示例
public class SimpleEnumDemo {
public static void main(String[] args) {
Season currentSeason = Season.SPRING;
// 遍历所有枚举值
for (Season season : Season.values()) {
System.out.println(season);
}
// 使用 switch
switch (currentSeason) {
case SPRING:
System.out.println("春天来了");
break;
case SUMMER:
System.out.println("夏天炎热");
break;
case AUTUMN:
System.out.println("秋天凉爽");
break;
case WINTER:
System.out.println("冬天寒冷");
break;
}
}
}
2.3 输出结果
SPRING
SUMMER
AUTUMN
WINTER
春天来了
三、带属性和方法的枚举
3.1 定义订单状态枚举
// 定义带属性的订单状态枚举
enum OrderStatus {
PENDING("待支付", 0),
PAID("已支付", 1),
SHIPPED("已发货", 2),
DELIVERED("已签收", 3),
CANCELLED("已取消", 4);
private final String description;
private final int code;
// 构造方法必须是 private
OrderStatus(String description, int code) {
this.description = description;
this.code = code;
}
public String getDescription() {
return description;
}
public int getCode() {
return code;
}
// 根据代码查找枚举
public static OrderStatus fromCode(int code) {
for (OrderStatus status : values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("Invalid code: " + code);
}
}
3.2 使用示例
public class EnumWithAttributesDemo {
public static void main(String[] args) {
OrderStatus status = OrderStatus.SHIPPED;
System.out.println("状态: " + status);
System.out.println("描述: " + status.getDescription());
System.out.println("代码: " + status.getCode());
// 使用 fromCode 方法
OrderStatus found = OrderStatus.fromCode(1);
System.out.println("代码1对应: " + found);
}
}
3.3 输出结果
状态: SHIPPED
描述: 已发货
代码: 2
代码1对应: PAID
四、实现接口的枚举
4.1 定义支付接口和枚举
// 定义支付接口
interface PaymentProcessor {
void processPayment(double amount);
String getPaymentType();
}
// 枚举实现接口
enum PaymentType implements PaymentProcessor {
ALIPAY {
@Override
public void processPayment(double amount) {
System.out.printf("支付宝支付 %.2f 元%n", amount);
}
@Override
public String getPaymentType() {
return "支付宝";
}
},
WECHAT {
@Override
public void processPayment(double amount) {
System.out.printf("微信支付 %.2f 元%n", amount);
}
@Override
public String getPaymentType() {
return "微信支付";
}
},
CREDIT_CARD {
@Override
public void processPayment(double amount) {
System.out.printf("信用卡支付 %.2f 元%n", amount);
}
@Override
public String getPaymentType() {
return "信用卡";
}
}
}
4.2 使用示例
public class EnumInterfaceDemo {
public static void main(String[] args) {
processPayment(PaymentType.ALIPAY, 199.99);
processPayment(PaymentType.WECHAT, 88.88);
processPayment(PaymentType.CREDIT_CARD, 500.00);
}
private static void processPayment(PaymentType type, double amount) {
System.out.println("使用: " + type.getPaymentType());
type.processPayment(amount);
System.out.println("—");
}
}
4.3 输出结果
使用: 支付宝
支付宝支付 199.99 元
—
使用: 微信支付
微信支付 88.88 元
—
使用: 信用卡
信用卡支付 500.00 元
—
五、带抽象方法的枚举
5.1 定义运算符枚举
// 带抽象方法的运算符枚举
enum Operation {
ADD {
@Override
public double apply(double a, double b) {
return a + b;
}
},
SUBTRACT {
@Override
public double apply(double a, double b) {
return a – b;
}
},
MULTIPLY {
@Override
public double apply(double a, double b) {
return a * b;
}
},
DIVIDE {
@Override
public double apply(double a, double b) {
if (b == 0) throw new ArithmeticException("除数不能为零");
return a / b;
}
};
// 抽象方法,每个枚举实例必须实现
public abstract double apply(double a, double b);
}
5.2 使用示例
public class EnumAbstractMethodDemo {
public static void main(String[] args) {
double a = 10, b = 5;
for (Operation op : Operation.values()) {
System.out.printf("%.0f %s %.0f = %.2f%n",
a, op.name(), b, op.apply(a, b));
}
}
}
5.3 输出结果
10 ADD 5 = 15.00
10 SUBTRACT 5 = 5.00
10 MULTIPLY 5 = 50.00
10 DIVIDE 5 = 2.00
六、使用枚举实现单例模式
6.1 定义数据库连接单例
// 使用枚举实现单例模式(线程安全、序列化安全)
enum DatabaseConnection {
INSTANCE;
private Connection connection;
DatabaseConnection() {
// 模拟初始化
System.out.println("数据库连接初始化");
}
public Connection getConnection() {
if (connection == null) {
connection = createConnection();
}
return connection;
}
private Connection createConnection() {
// 实际项目中创建真实连接
return null;
}
public void close() {
// 关闭连接逻辑
}
}
6.2 使用示例
public class EnumSingletonDemo {
public static void main(String[] args) {
DatabaseConnection conn1 = DatabaseConnection.INSTANCE;
DatabaseConnection conn2 = DatabaseConnection.INSTANCE;
System.out.println("是否为同一实例: " + (conn1 == conn2));
}
}
6.3 输出结果
数据库连接初始化
是否为同一实例: true
为什么枚举实现单例是最佳实践?
- 线程安全:由 JVM 保证
- 序列化安全:枚举的序列化机制保证了单例的唯一性
- 代码简洁:比传统实现方式更加优雅
七、使用枚举实现策略模式
7.1 定义折扣策略枚举
// 使用枚举实现折扣策略
enum DiscountStrategy {
NO_DISCOUNT {
@Override
public double calculate(double originalPrice) {
return originalPrice;
}
},
TEN_PERCENT_OFF {
@Override
public double calculate(double originalPrice) {
return originalPrice * 0.9;
}
},
TWENTY_PERCENT_OFF {
@Override
public double calculate(double originalPrice) {
return originalPrice * 0.8;
}
},
HALF_PRICE {
@Override
public double calculate(double originalPrice) {
return originalPrice * 0.5;
}
};
public abstract double calculate(double originalPrice);
}
7.2 使用示例
public class EnumStrategyDemo {
public static void main(String[] args) {
double price = 1000;
for (DiscountStrategy strategy : DiscountStrategy.values()) {
double finalPrice = strategy.calculate(price);
System.out.printf("%s: %.2f -> %.2f%n",
strategy.name(), price, finalPrice);
}
}
}
7.3 输出结果
NO_DISCOUNT: 1000.00 -> 1000.00
TEN_PERCENT_OFF: 1000.00 -> 900.00
TWENTY_PERCENT_OFF: 1000.00 -> 800.00
HALF_PRICE: 1000.00 -> 500.00
八、枚举的常用方法
8.1 方法列表
| values() | 获取所有枚举值,返回数组 |
| valueOf(String name) | 根据名称获取枚举实例 |
| name() | 获取枚举常量的名称 |
| ordinal() | 获取枚举常量的序号(从0开始) |
| compareTo() | 比较枚举常量的序号 |
| equals() | 比较两个枚举常量是否相等 |
| hashCode() | 返回枚举常量的哈希码 |
8.2 使用示例
public class EnumMethodsDemo {
public static void main(String[] args) {
// values() – 获取所有枚举值
Season[] seasons = Season.values();
// valueOf() – 根据名称获取枚举
Season spring = Season.valueOf("SPRING");
// name() – 获取枚举名称
String name = spring.name();
// ordinal() – 获取枚举序号(从0开始)
int index = spring.ordinal();
// compareTo() – 比较枚举
int compare = Season.SUMMER.compareTo(Season.SPRING);
// equals() 和 hashCode()
boolean same = Season.SUMMER.equals(Season.valueOf("SUMMER"));
}
}
九、关键要点总结
9.1 枚举的特性
| 构造方法 | 默认是 private,只能声明枚举实例时调用 |
| 单例特性 | 每个枚举常量都是该枚举类型的一个实例,且全局唯一 |
| 线程安全 | 枚举实例由 JVM 保证线程安全 |
| 序列化 | 枚举的序列化机制保证了单例的唯一性 |
9.2 最佳实践
9.3 注意事项
- 枚举不能被继承(所有枚举隐式继承自 java.lang.Enum)
- 枚举可以实现接口
- 枚举可以包含抽象方法,每个实例必须实现
- 枚举的 equals() 方法可以直接使用 == 替代



