在 Java 中,枚举(Enum)是一种特殊的数据类型,用于定义一组固定的命名常量。它比传统的常量(如 public static final
)更安全、更灵活,且支持面向对象特性。以下是枚举的详细用法:
1. 基础定义与使用
java
复制
下载
public enum Direction {NORTH, SOUTH, EAST, WEST // 枚举常量(全大写命名) }// 使用示例 Direction dir = Direction.NORTH; System.out.println(dir); // 输出: NORTH
2. 添加成员变量和方法
枚举可以有字段、构造方法和自定义方法:
java
复制
下载
public enum Planet {// 枚举常量 + 构造参数MERCURY(3.303e23, 2.4397e6),VENUS(4.869e24, 6.0518e6);private final double mass; // 质量(kg)private final double radius; // 半径(m)// 构造方法(必须是 private)Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}// 自定义方法public double surfaceGravity() {return 6.67430e-11 * mass / (radius * radius);} }// 使用 double gravity = Planet.MERCURY.surfaceGravity();
3. 覆盖枚举常量的方法
每个常量可以有自己的方法实现:
java
复制
下载
public enum Operation {ADD {public double apply(double x, double y) { return x + y; }},SUBTRACT {public double apply(double x, double y) { return x - y; }};public abstract double apply(double x, double y); // 抽象方法 }// 使用 double result = Operation.ADD.apply(5, 3); // 返回 8
4. 常用内置方法
-
values()
:获取所有枚举值 -
valueOf(String name)
:通过名称获取枚举常量 -
name()
和ordinal()
:获取常量名和顺序位置
java
复制
下载
Direction[] allDirections = Direction.values(); // [NORTH, SOUTH, EAST, WEST] Direction east = Direction.valueOf("EAST"); // 字符串转枚举 System.out.println(east.name()); // 输出 "EAST" System.out.println(east.ordinal()); // 输出 2(索引从0开始)
5. 实现接口
枚举可以实现接口,统一或分别实现方法:
java
复制
下载
public interface Command {void execute(); }public enum FileOperation implements Command {OPEN {public void execute() { System.out.println("打开文件"); }},SAVE {public void execute() { System.out.println("保存文件"); }}; }// 使用 FileOperation.OPEN.execute(); // 输出 "打开文件"
6. 在 switch 语句中使用
java
复制
下载
Direction dir = Direction.NORTH; switch (dir) {case NORTH:System.out.println("向北");break;case SOUTH:System.out.println("向南");break;// ...其他 case }
7. 单例模式(线程安全)
枚举是实现单例的最佳方式(避免反射攻击):
java
复制
下载
public enum Singleton {INSTANCE;public void doSomething() {System.out.println("单例操作");} }// 使用 Singleton.INSTANCE.doSomething();
关键特性总结
特性 | 说明 |
---|---|
类型安全 | 编译时检查,避免传入无效值 |
固定实例 | 枚举常量在 JVM 中是唯一的(== 比较安全) |
支持 OOP | 可包含字段、方法、构造方法,实现接口,覆盖方法 |
线程安全 | 枚举实例的创建由 JVM 保证,天然适合单例 |
序列化安全 | 无需额外处理,Java 原生支持枚举的序列化与反序列化 |
何时使用枚举?
-
需要一组预定义的常量(如状态、类型、方向等)
-
需要类型安全且易读的常量
-
需要为常量附加行为(方法)
-
实现单例模式
通过合理使用枚举,可以大幅提升代码的可读性、安全性和可维护性。
Java 枚举类型完整示例
下面是一个完整的Java枚举使用示例,展示了枚举的各种特性:
import java.time.DayOfWeek;public class EnumExample {// 1. 基本枚举定义public enum Season {SPRING, SUMMER, AUTUMN, WINTER}// 2. 带属性和方法的枚举public enum Planet {MERCURY(3.303e23, 2.4397e6),VENUS(4.869e24, 6.0518e6),EARTH(5.976e24, 6.37814e6),MARS(6.421e23, 3.3972e6),JUPITER(1.9e27, 7.1492e7),SATURN(5.688e26, 6.0268e7),URANUS(8.686e25, 2.5559e7),NEPTUNE(1.024e26, 2.4746e7);private final double mass; // 千克private final double radius; // 米// 私有构造函数Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}public double getMass() {return mass;}public double getRadius() {return radius;}// 计算表面重力public double surfaceGravity() {final double G = 6.67430e-11; // 引力常数return G * mass / (radius * radius);}// 计算重量public double surfaceWeight(double otherMass) {return otherMass * surfaceGravity();}}// 3. 带抽象方法的枚举public enum Operation {ADD("+") {public double apply(double x, double y) {return x + y;}},SUBTRACT("-") {public double apply(double x, double y) {return x - y;}},MULTIPLY("*") {public double apply(double x, double y) {return x * y;}},DIVIDE("/") {public double apply(double x, double y) {if (y == 0) throw new ArithmeticException("Division by zero");return x / y;}};private final String symbol;Operation(String symbol) {this.symbol = symbol;}public String getSymbol() {return symbol;}// 抽象方法 - 每个枚举常量必须实现public abstract double apply(double x, double y);}// 4. 枚举实现接口public interface WorkSchedule {String getSchedule();}public enum WorkDay implements WorkSchedule {MONDAY("09:00-17:00") {public String getMotivation() {return "New week, new opportunities!";}},TUESDAY("09:00-17:00") {public String getMotivation() {return "Keep the momentum going!";}},WEDNESDAY("09:00-17:00") {public String getMotivation() {return "Halfway there!";}},THURSDAY("09:00-17:00") {public String getMotivation() {return "Almost there!";}},FRIDAY("09:00-16:00") {public String getMotivation() {return "Weekend is near!";}},SATURDAY("Day Off") {public String getMotivation() {return "Enjoy your weekend!";}},SUNDAY("Day Off") {public String getMotivation() {return "Rest and recharge!";}};private final String schedule;WorkDay(String schedule) {this.schedule = schedule;}@Overridepublic String getSchedule() {return schedule;}// 每个枚举常量可以有自己的方法实现public abstract String getMotivation();}public static void main(String[] args) {// 1. 基本枚举使用System.out.println("===== 基本枚举使用 =====");Season currentSeason = Season.SUMMER;System.out.println("当前季节: " + currentSeason);System.out.println("所有季节:");for (Season season : Season.values()) {System.out.println(season);}System.out.println();// 2. 带属性和方法的枚举System.out.println("===== 行星信息 =====");double earthWeight = 70; // 千克Planet earth = Planet.EARTH;System.out.printf("地球表面重力: %.2f m/s²%n", earth.surfaceGravity());System.out.printf("地球上 %.1f kg 的重量相当于: %n", earthWeight);for (Planet p : Planet.values()) {System.out.printf("在 %-8s上的重量: %6.1f kg%n", p, p.surfaceWeight(earthWeight));}System.out.println();// 3. 带抽象方法的枚举System.out.println("===== 数学运算 =====");double x = 10, y = 4;for (Operation op : Operation.values()) {System.out.printf("%.1f %s %.1f = %.1f%n", x, op.getSymbol(), y, op.apply(x, y));}System.out.println();// 4. 枚举实现接口System.out.println("===== 工作日安排 =====");DayOfWeek today = java.time.LocalDate.now().getDayOfWeek();WorkDay currentDay = WorkDay.valueOf(today.toString());System.out.println("今天是: " + currentDay);System.out.println("工作时间: " + currentDay.getSchedule());System.out.println("每日激励: " + currentDay.getMotivation());System.out.println();// 5. 在switch语句中使用枚举System.out.println("===== 根据季节推荐活动 =====");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;}System.out.println();// 6. 单例模式System.out.println("===== 单例模式 =====");AppConfig config = AppConfig.INSTANCE;config.setAppName("Enum Demo App");System.out.println("应用名称: " + config.getAppName());System.out.println("配置ID: " + config.getConfigId());}// 7. 使用枚举实现单例模式public enum AppConfig {INSTANCE;private String appName;private final String configId = "CONFIG-" + System.currentTimeMillis();public String getAppName() {return appName;}public void setAppName(String appName) {this.appName = appName;}public String getConfigId() {return configId;}}
}
示例说明
1. 基本枚举 (Season)
-
最简单的枚举形式,只有一组命名常量
-
使用
values()
方法遍历所有枚举值 -
直接打印枚举常量会输出其名称
2. 带属性和方法的枚举 (Planet)
-
每个行星有质量和半径属性
-
提供计算表面重力和重量的方法
-
展示了如何使用枚举的构造函数初始化属性
3. 带抽象方法的枚举 (Operation)
-
定义抽象方法
apply()
,每个枚举常量必须实现 -
每个运算有自己的符号表示
-
演示了如何为不同枚举常量提供不同行为
4. 实现接口的枚举 (WorkDay)
-
实现
WorkSchedule
接口 -
每个工作日有自己的时间安排
-
每个枚举常量有自己的激励语实现
-
结合Java 8的日期API获取当前星期几
5. switch语句中使用枚举
-
根据当前季节推荐不同的活动
-
展示了枚举在switch语句中的类型安全特性
6. 单例模式实现 (AppConfig)
-
使用枚举实现线程安全的单例
-
包含配置属性和访问方法
-
展示了枚举如何防止反射攻击和序列化问题
运行结果
运行此程序将输出类似以下内容(具体结果取决于运行时的日期):
text
复制
下载
===== 基本枚举使用 ===== 当前季节: SUMMER 所有季节: SPRING SUMMER AUTUMN WINTER===== 行星信息 ===== 地球表面重力: 9.80 m/s² 地球上 70.0 kg 的重量相当于: 在 MERCURY 上的重量: 26.4 kg 在 VENUS 上的重量: 63.1 kg 在 EARTH 上的重量: 70.0 kg 在 MARS 上的重量: 26.5 kg 在 JUPITER 上的重量: 177.0 kg 在 SATURN 上的重量: 74.9 kg 在 URANUS 上的重量: 63.5 kg 在 NEPTUNE 上的重量: 79.6 kg===== 数学运算 ===== 10.0 + 4.0 = 14.0 10.0 - 4.0 = 6.0 10.0 * 4.0 = 40.0 10.0 / 4.0 = 2.5===== 工作日安排 ===== 今天是: WEDNESDAY 工作时间: 09:00-17:00 每日激励: Halfway there!===== 根据季节推荐活动 ===== 夏天活动: 游泳、露营===== 单例模式 ===== 应用名称: Enum Demo App 配置ID: CONFIG-1717999999999
这个示例全面展示了Java枚举的各种特性,包括基本用法、带属性和方法的枚举、抽象方法实现、接口实现、在switch语句中使用以及实现单例模式。