😫 痛点引入 :项目里一堆魔法数字和字符串?
if (status == 1)谁知道 1 代表啥?用常量类又怕写错值?枚举来救你!枚举把固定的选项封装成类型安全的常量,编译期就能检查,再也不怕写错!✨
一、枚举是什么?🤔
1.1 官方定义
枚举(enum) :当一个类型的对象个数固定时,就可以使用枚举类型。
1.2 生活类比
枚举就像菜单上的固定选项 📋:
你去餐厅点菜:
❌ 错误方式:我要第3个(服务员不知道3是啥)
✅ 正确方式:我要红烧肉(明确、不会点错)
枚举就是把"红烧肉、宫保鸡丁、鱼香肉丝"
变成一个个固定的选项,不会写错、不会写漏
1.3 典型使用场景
| 场景 | 固定选项 | 适合用枚举 |
|---|---|---|
| 星期 | 周一~周日(7个) | ✅ |
| 月份 | 1月~12月(12个) | ✅ |
| 季节 | 春夏秋冬(4个) | ✅ |
| 订单状态 | 待付款/已付款/已发货/已完成 | ✅ |
| 用户角色 | 管理员/普通用户/VIP | ✅ |
| 方向 | 上下左右 | ✅ |
1.4 一句话总结
枚举 = 实例个数固定的特殊类 ,源文件是
.java,编译后是.class📦
二、enum 关键字定义枚举 🏗️
2.1 基本格式
java
访问修饰符 enum 枚举名 {
枚举项1, 枚举项2, 枚举项3, ... 枚举项n;
}
2.2 最简单的枚举
java
// 定义季节枚举
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
class Demo01 {
public static void main(String[] args) {
// 直接用 类名.枚举项 访问
Season s = Season.SPRING;
System.out.println(s); // SPRING
}
}
2.3 带成员变量的枚举(常用 ⭐)
java
public enum WeekDay {
// 枚举项 = 枚举类型的对象,默认 public static final 修饰
// 如果有构造方法,必须在枚举项后传参
MON("星期一") {
@Override
public void show() {
System.out.println("愉快的周一,新的一周开始啦 💪");
}
},
TUE("星期二") {
@Override
public void show() {
System.out.println("愉快的周二,渐入佳境 📈");
}
},
WED("星期三") {
@Override
public void show() {
System.out.println("愉快的周三,一周过半啦 🎉");
}
},
THU("星期四") {
@Override
public void show() {
System.out.println("愉快的周四,快到周五了 ⏳");
}
},
FRI("星期五") {
@Override
public void show() {
System.out.println("愉快的周五,马上放假!🥳");
}
},
SAT("星期六") {
@Override
public void show() {
System.out.println("愉快的周六,睡到自然醒 😴");
}
},
SUN("星期日") {
@Override
public void show() {
System.out.println("愉快的周日,珍惜最后一天 🌅");
}
};
// 成员变量
private String weekDayName;
// 构造方法(必须是 private,不写默认也是 private)
WeekDay(String weekDayName) {
this.weekDayName = weekDayName;
}
// getter/setter
public String getWeekDayName() {
return weekDayName;
}
public void setWeekDayName(String weekDayName) {
this.weekDayName = weekDayName;
}
// 抽象方法:每个枚举项必须重写
public abstract void show();
}
class Demo02 {
public static void main(String[] args) {
WeekDay day = WeekDay.FRI;
System.out.println(day.getWeekDayName()); // 星期五
day.show(); // 愉快的周五,马上放假!🥳
}
}
三、枚举的 7 大特点 📋
| 序号 | 特点 | 说明 |
|---|---|---|
| 1 | 父类是 Enum | 所有枚举类默认继承 java.lang.Enum |
| 2 | 类名.枚举项访问 | WeekDay.MON 直接访问 |
| 3 | 枚举项就是对象 | 默认 public static final 修饰 |
| 4 | 第一行必须是枚举项 | 最后一个枚举项后加分号(有其他内容时不能省略) |
| 5 | 可以有成员变量 | 和普通类一样 |
| 6 | 构造方法必须私有 | 不写修饰符默认也是 private,不允许 public |
| 7 | 可以有抽象方法 | 每个枚举项必须重写,类似匿名内部类 |
3.1 ⚠️ 关键细节
枚举项后面的分号:
java
// ✅ 没有其他内容,分号可省略
public enum Color {
RED, GREEN, BLUE
}
// ✅ 有其他内容,分号不能省略
public enum Color {
RED, GREEN, BLUE; // ← 分号必须有!
private String desc;
}
构造方法私有:
java
public enum WeekDay {
MON, TUE, WED;
// ❌ 编译错误!枚举的构造方法不能是 public
// public WeekDay() {}
// ✅ 私有构造(正确)
private WeekDay() {}
// ✅ 不写修饰符也行(默认私有)
// WeekDay() {}
}
四、枚举常用方法速查 📖
4.1 方法一览表
| 方法 | 功能 | 返回值 |
|---|---|---|
ordinal() |
获取枚举序数(从0开始) | int |
compareTo(E o) |
比较两个枚举项的顺序 | int(调用者序数 - 参数序数) |
name() |
获取枚举项名称 | String |
toString() |
获取枚举项名称(可重写) | String |
values() |
获取所有枚举项 | 枚举类型数组 |
valueOf(String name) |
根据名称获取枚举项 | 枚举类型 |
4.2 代码示例
java
public class Demo03 {
public static void main(String[] args) {
// ordinal():获取序数(从0开始)
WeekDay mon = WeekDay.MON;
WeekDay tue = WeekDay.TUE;
WeekDay wed = WeekDay.WED;
System.out.println("MON序数:" + mon.ordinal()); // 0
System.out.println("TUE序数:" + tue.ordinal()); // 1
System.out.println("WED序数:" + wed.ordinal()); // 2
// compareTo():比较顺序
System.out.println("WED - MON = " + wed.compareTo(mon)); // 2
// name() vs toString()
System.out.println("name():" + wed.name()); // WED
System.out.println("toString():" + wed.toString()); // WED
// 区别:name()不可重写,toString()可以重写
// values():获取所有枚举项
System.out.println("--- 遍历所有枚举项 ---");
WeekDay[] days = WeekDay.values();
for (WeekDay day : days) {
System.out.println(day.ordinal() + " → " + day.getWeekDayName());
}
// valueOf():根据名称获取枚举项
WeekDay friday = WeekDay.valueOf("FRI");
System.out.println("valueOf:" + friday.getWeekDayName()); // 星期五
}
}
五、枚举实现接口 🔗
5.1 为什么枚举要实现接口?
枚举不能继承 其他类(已经继承了 Enum),但可以实现接口,实现多态。
5.2 两种实现方式
方式一:统一实现(所有枚举项行为一致)
java
interface Printable {
void print();
}
// 所有枚举项共享同一个实现
enum Color implements Printable {
RED, GREEN, BLUE;
@Override
public void print() {
System.out.println("颜色:" + this.name());
}
}
class Demo04 {
public static void main(String[] args) {
Color.RED.print(); // 颜色:RED
Color.GREEN.print(); // 颜色:GREEN
}
}
方式二:分别实现(每个枚举项行为不同)⭐ 更常用
java
interface Behavior {
void action();
}
enum Player implements Behavior {
WARRIOR("战士") {
@Override
public void action() {
System.out.println("战士:挥剑攻击!⚔️");
}
},
MAGE("法师") {
@Override
public void action() {
System.out.println("法师:释放火球术!🔥");
}
},
HEALER("治疗") {
@Override
public void action() {
System.out.println("治疗:恢复生命值!💚");
}
};
private String name;
Player(String name) {
this.name = name;
}
public String getRoleName() {
return name;
}
}
class Demo05 {
public static void main(String[] args) {
for (Player p : Player.values()) {
System.out.print(p.getRoleName() + " → ");
p.action();
}
// 战士 → 战士:挥剑攻击!⚔️
// 法师 → 法师:释放火球术!🔥
// 治疗 → 治疗:恢复生命值!💚
}
}
六、枚举在 switch 中的使用 🔀
6.1 switch + 枚举 = 天然搭档
switch 语句天然支持枚举类型,不需要写枚举类名前缀!
java
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
class Demo06 {
public static void main(String[] args) {
Season season = Season.SUMMER;
// switch 中使用枚举
switch (season) {
case SPRING: // ⚠️ 不需要写 Season.SPRING,直接写枚举项名
System.out.println("春天:万物复苏 🌸");
break;
case SUMMER:
System.out.println("夏天:烈日炎炎 ☀️");
break;
case AUTUMN:
System.out.println("秋天:硕果累累 🍂");
break;
case WINTER:
System.out.println("冬天:银装素裹 ❄️");
break;
}
}
}
6.2 ⚠️ switch 枚举注意点
java
// ❌ 错误:不要写枚举类名
switch (season) {
case Season.SPRING: // 编译错误!
}
// ✅ 正确:直接写枚举项名
switch (season) {
case SPRING: // 正确
}
6.3 实战:订单状态流转
java
enum OrderStatus {
UNPAID, // 待付款
PAID, // 已付款
SHIPPED, // 已发货
COMPLETED, // 已完成
CANCELLED // 已取消
}
class Demo07 {
public static void main(String[] args) {
OrderStatus status = OrderStatus.PAID;
switch (status) {
case UNPAID:
System.out.println("订单待付款,请尽快支付 💰");
break;
case PAID:
System.out.println("订单已支付,等待发货 📦");
break;
case SHIPPED:
System.out.println("订单已发货,注意查收 🚚");
break;
case COMPLETED:
System.out.println("订单已完成,感谢购买 ✅");
break;
case CANCELLED:
System.out.println("订单已取消 ❌");
break;
}
}
}
七、枚举 vs 常量类------面试常问 💼
7.1 常量类写法
java
// 传统常量类
class StatusConstant {
public static final int UNPAID = 0;
public static final int PAID = 1;
public static final int SHIPPED = 2;
public static final int COMPLETED = 3;
}
7.2 对比表(面试必背 ⭐)
| 对比项 | 常量类 | 枚举 |
|---|---|---|
| 类型安全 | ❌ if (status == 999) 不报错 |
✅ 编译期检查,写错就报错 |
| 命名空间 | ❌ 全局污染 | ✅ OrderStatus.PAID 自带命名空间 |
| 可读性 | ❌ 魔法数字,看不懂 | ✅ PAID 一目了然 |
| switch 支持 | ✅ 支持 int | ✅ 支持 enum(更好) |
| 可以定义方法 | ❌ 不行 | ✅ 每个枚举项可以有自己的行为 |
| 可以遍历 | ❌ 不行 | ✅ values() 遍历所有值 |
| 单例保证 | ❌ 无法保证 | ✅ 每个枚举项都是单例 |
| 实现接口 | ❌ 不行 | ✅ 可以实现多态 |
7.3 代码示例:枚举的优势
java
class Demo08 {
public static void main(String[] args) {
// ❌ 常量类:容易写错,编译器不检查
int status = 999; // 啥啊?编译不报错!
if (status == StatusConstant.UNPAID) {
System.out.println("待付款");
}
// ✅ 枚举:编译期检查,写错直接报错
OrderStatus status2 = OrderStatus.PAID; // 编译器保证不会写错
// OrderStatus status3 = OrderStatus.ABCD; // 编译错误!不存在这个值
// ✅ 遍历所有枚举项
System.out.println("--- 所有订单状态 ---");
for (OrderStatus s : OrderStatus.values()) {
System.out.println(s.ordinal() + " → " + s.name());
}
}
}
八、实战:季节枚举 + 状态机 💪
8.1 需求
定义一个季节枚举,每个季节有自己的特点描述,并且能够根据当前季节判断下一个季节是什么。
8.2 代码实现
java
enum Season {
SPRING("春天", "万物复苏,适合播种 🌱") {
@Override
public Season next() {
return SUMMER;
}
},
SUMMER("夏天", "烈日炎炎,适合游泳 🏊") {
@Override
public Season next() {
return AUTUMN;
}
},
AUTUMN("秋天", "硕果累累,适合收割 🌾") {
@Override
public Season next() {
return WINTER;
}
},
WINTER("冬天", "银装素裹,适合冬眠 ❄️") {
@Override
public Season next() {
return SPRING;
}
};
private String name;
private String desc;
Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
// 抽象方法:获取下一个季节
public abstract Season next();
// 普通方法:打印季节信息
public void printInfo() {
System.out.println(name + ":" + desc);
}
}
class Demo09 {
public static void main(String[] args) {
// 打印所有季节信息
System.out.println("=== 四季轮回 ===");
for (Season s : Season.values()) {
s.printInfo();
}
// 状态机:从春天开始,打印下一个季节
System.out.println("\n=== 季节流转 ===");
Season current = Season.SPRING;
for (int i = 0; i < Season.values().length; i++) {
System.out.println("当前:" + current.getName());
current = current.next();
}
}
}
运行结果:
=== 四季轮回 ===
春天:万物复苏,适合播种 🌱
夏天:烈日炎炎,适合游泳 🏊
秋天:硕果累累,适合收割 🌾
冬天:银装素裹,适合冬眠 ❄️
=== 季节流转 ===
当前:春天
当前:夏天
当前:秋天
当前:冬天
本篇总结 📝
- 枚举基础 🤔:实例个数固定的特殊类,编译后是 .class
- enum 定义 🏗️:枚举项就是对象,第一行必须是枚举项
- 7 大特点 📋:父类是 Enum、构造方法私有、可定义抽象方法等
- 常用方法 📖:ordinal/compareTo/name/toString/values/valueOf
- 实现接口 🔗:枚举可以实现接口,每个枚举项可以有不同行为
- switch 使用 🔀:天然支持,直接写枚举项名,不用前缀
- 枚举 vs 常量类 💼:类型安全、命名空间、可遍历、可定义方法
- 实战演练 💪:季节枚举 + 状态机,next() 方法实现流转
作者 :书源丶
发布平台:CSDN