枚举是一种定义固定常量集合的类,
它让代码更严谨、更安全、更优雅,
并且每个枚举项都是一个对象,
可以有自己的属性和方法。
一、为什么会有枚举?
问题背景:
假设你要表示四个季节:
春、夏、秋、冬
最早的时候,大家可能这么写:
class Season {
int SPRING = 1;
int SUMMER = 2;
int AUTUMN = 3;
int WINTER = 4;
}
这样当然能用,但问题是:
- 使用者不知道应该传什么值。
- 写错也不会报错,比如 useSeason(10); 编译器不会警告。
- 代码提示不友好(输入参数只显示“int”)。
所以后来人们用上了 常量 + static final:
class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
这样做虽然可以标记出不同的季节,但有两个明显的弊端:
1.入参不严谨:
比如你写了一个方法:
public static void useSeason(int season) {
switch (season) {
case 1: System.out.println("春季"); break;
case 2: System.out.println("夏季"); break;
case 3: System.out.println("秋季"); break;
case 4: System.out.println("冬季"); break;
}
}
调用时别人可能这样传:
useSeason(5); // 没有错误,但5是什么季节??
这个值完全错误,但编译器不会报错,这就是入参不严谨的问题。
2.提示性不强:
- IDE 只知道这个参数是 int 类型,没有任何提示到底该传 1、2、3、还是 4。
- 比如在 IntelliJ 或 Eclipse 中写 useSeason( 时,不会有智能提示。
于是 —— 枚举(enum) 出场了!
二、什么是枚举?
枚举是一种特殊的“类”,用来表示有限且固定的一组常量。
比如:
- 季节,只有春夏秋冬;
- 性别,只有男和女;
- 订单状态,只有“已支付”“未支付”“已发货”“已完成”。
定义如下:

enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
实际上,枚举做了两件事:
- 定义了一个类 Season。
- 在这个类中自动创建了四个对象:SPRING, SUMMER, AUTUMN, WINTER。
你可以理解为:
class Season {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
private Season() {} // 构造器是私有的,防止别人随便创建新对象
}
是不是感觉很像常量?
但比常量更强的是:它限定类型。比如:
public static void useSeason(Season season) { ... }
现在这个方法只能传入 Season 枚举类型的值,
如果你写 useSeason(1),编译器直接报错。
- 只能传入 Season 类型的对象;
- IDE 自动提示可选项;
- 调用时可读性强:Season.SPRING 一眼就知道意思;
- 传错类型直接编译不通过。
三、枚举的本质
“枚举其实就是一种特殊的类。”
在底层,Java 编译器会帮你把上面的枚举编译成类似这样:
class Season extends Enum<Season> {
public static final Season SPRING = new Season("SPRING", 0);
public static final Season SUMMER = new Season("SUMMER", 1);
public static final Season AUTUMN = new Season("AUTUMN", 2);
public static final Season WINTER = new Season("WINTER", 3);
private Season(String name, int ordinal) {
super(name, ordinal);
}
}
所以:
- 每个枚举项就是一个对象;
- 枚举的构造方法是 private 的;
- 每个对象有两个默认属性:
- name():枚举项名字(如 “SPRING”)
- ordinal():枚举项序号(从 0 开始)
四、枚举的常用方法
| 方法 | 说明 | 示例 |
| name() | 返回枚举项的名称 | Season.SPRING.name()→ "SPRING" |
| ordinal() | 返回枚举项的序号(从 0 开始) | Season.WINTER.ordinal() → 3 |
| values() | 返回所有枚举项数组 | for (Season s : Season.values()) {...} |
| valueOf (String name) | 将字符串转为枚举项 | Season.valueOf("SUMMER")→Season.SUMMER |
五、枚举的高级用法(带属性和构造方法)
枚举不仅能列出固定项,还能像类,带属性和方法。
示例:
public class EnumTest {
public static void main(String[] args) {
useSeason(Season.AUTUMN);
System.out.println(Season.SUMMER.getChineseName());
System.out.println(Season.SUMMER.getDescription());
System.out.println(Season.SUMMER.ordinal());
System.out.println(Season.AUTUMN.ordinal());
}
public static void useSeason(Season season){
switch (season){
case SPRING:
System.out.println("春季");
break;
case SUMMER:
System.out.println("夏季");
break;
case AUTUMN:
System.out.println("秋季");
break;
case WINTER:
System.out.println("冬季");
break;
}
}
}
enum Season{
SPRING("春天","温暖"),
SUMMER("夏天", "炎热"),
AUTUMN("秋天", "凉爽"),
WINTER("冬天", "寒冷");
private final String chineseName;
private final String description;
private Season(String chineseName,String description){
this.chineseName=chineseName;
this.description=description;
}
public String getChineseName(){
return chineseName;
}
public String getDescription(){
return description;
}
}

六、枚举可以定义抽象方法
可以让每个枚举项重写自己的行为:
enum Operation {
ADD {
public double apply(double a, double b) { return a + b; }
},
SUBTRACT {
public double apply(double a, double b) { return a - b; }
},
MULTIPLY {
public double apply(double a, double b) { return a * b; }
},
DIVIDE {
public double apply(double a, double b) { return a / b; }
};
// 定义抽象方法(每个枚举项必须实现)
public abstract double apply(double a, double b);
}
逐层解释:
(1) public abstract double apply(double a, double b);
//定义抽象方法(每个枚举项必须实现)
public abstract double apply(double a, double b);
这一行表示:
每个枚举项都必须实现自己的“计算方式”。
这就像在接口中定义了一个抽象方法,强制所有实现类都去实现它。
而每个枚举项(ADD、SUBTRACT…)就相当于是一个“子类对象”,它各自重写了这个方法。
(2) 每个枚举项后面的大括号 {} 是什么意思?
这些大括号其实代表“匿名子类的实现体”。
也就是说,每个枚举项都是一个“Operation 的子类对象”,
并且在这个对象内部重写了 apply 方法。
可以把它想象成下面的逻辑(伪代码):
Operation ADD = new Operation() {
public double apply(double a, double b) { return a + b; }
};
Operation SUBTRACT = new Operation() {
public double apply(double a, double b) { return a - b; }
};
...
所以 Operation.ADD 其实是一个对象,并且它有自己版本的 apply() 方法。
(3) 调用时是怎么执行的?
System.out.println(Operation.ADD.apply(3, 5)); // 3 + 5 = 8
System.out.println(Operation.SUBTRACT.apply(3, 5)); // 3 - 5 = -2
System.out.println(Operation.MULTIPLY.apply(3, 5)); // 3 * 5 = 15
System.out.println(Operation.DIVIDE.apply(10, 5)); // 10 / 5 = 2
当你写 Operation.ADD.apply(3, 5) 时,
Java 会自动调用 ADD 这个枚举项对象内部定义的 apply() 方法,也就是执行加法逻辑。
换句话说,每个枚举项都拥有属于自己的方法实现。
而调用时,系统会自动执行对应枚举项的版本。
七、枚举的特点和应用场景
| 特点 | 通俗解释 |
| 每个枚举项是该枚举的一个对象 | 就像类的实例,只不过对象是固定的,不会变 |
| 通过枚举类名访问 | 比如 Season.SPRING |
| 所有枚举类都是 Enum 的子类 | 所以能用 .ordinal()、.name() 等方法 |
| 枚举可以定义成员变量 | 就像普通类一样,可以加字段、构造器、方法 |
| 枚举项必须写在第一行 | 因为编译器需要先生成这些对象 |
| 枚举的构造器是 private | 防止外部创建新的枚举对象 |
| 枚举可以定义抽象方法 | 但所有枚举项都要实现它 |
| 场景 | 示例 |
| 性别 | Gender.MALE / Gender.FEMALE |
| 订单状态 | OrderStatus.NEW / PAID / SHIPPED / DONE |
| 文件类型 | FileType.TXT / PDF / DOC |
| 支付方式 | PayType.ALIPAY / WECHAT / CARD |
例如订单状态:
enum OrderStatus {
NEW("待支付"),
PAID("已支付"),
SHIPPED("已发货"),
DONE("已完成");
private final String desc;
OrderStatus(String desc) { this.desc = desc; }
public String getDesc() { return desc; }
}
使用:
OrderStatus status = OrderStatus.NEW;
System.out.println(status.getDesc()); // 待支付
1505

被折叠的 条评论
为什么被折叠?



