在 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/s2%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/s2 地球上 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語句中使用以及實現單例模式。
?