实用指南:Java基础(十四):枚举类详解

news/2025/9/26 16:07:58/文章来源:https://www.cnblogs.com/lxjshuju/p/19113695

Java基础系列文章

Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建

Java基础(二):八种基本数据类型详解

Java基础(三):逻辑运算符详解

Java基础(四):位运算符详解

Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南

Java基础(六):数组全面解析

Java基础(七): 面向过程与面向对象、类与对象、成员变量与局部变量、值传递与引用传递、方法重载与方法重写

Java基础(八):封装、继承、多态与关键字this、super详解

Java基础(九):Object核心类深度剖析

Java基础(十):关键字static详解

Java基础(十一):关键字final详解

Java基础(十二):抽象类与接口详解

Java基础(十三):内部类详解

Java基础(十四):枚举类详解

目录

  • 一、枚举类概述
  • 二、基本枚举定义
    • 1、最简单的枚举
    • 2、带有属性和方法的枚举
    • 3、枚举的特点
  • 三、枚举方法和工具类
    • 1、枚举的隐含方法和属性
    • 2、工具类EnumSet/EnumMap
  • 四、枚举实现接口
  • 五、枚举的单例模式
    • 1、为什么使用枚举实现单例?
    • 2、对比传统单例写法(如双重检查锁、静态内部类等)

一、枚举类概述

枚举(Enum)是Java 5引入的一种特殊数据类型,它允许我们预定义一组常量。在Java中,枚举是一种特殊的类,它继承自java.lang.Enum类,具有类的所有特性。

为什么需要枚举?

  • 在枚举出现之前,我们通常使用以下方式表示一组常量
public 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. 类型系统约束​:枚举变量只能接受特定的枚举常量,传统常量编译时不能校验合法性
  2. 可读性差​:数字本身没有表达其含义,难以理解
  3. 无法添加属性或方法
  4. 难以维护​:如果常量值需要修改,可能影响多处代码

枚举解决了这些问题,提供了更安全、更强大的常量表示方式。

二、基本枚举定义

1、最简单的枚举

public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

编译器生成的大致等价代码:

// 编译器生成的类,实际名称仍然是 Day,继承自 java.lang.Enum
public final class Day
extends Enum<
Day> {
// 枚举实例,是 Day 类的静态 final 实例,每个都是唯一的
public static final Day SUNDAY = new Day("SUNDAY", 0);
public static final Day MONDAY = new Day("MONDAY", 1);
public static final Day TUESDAY = new Day("TUESDAY", 2);
public static final Day WEDNESDAY = new Day("WEDNESDAY", 3);
public static final Day THURSDAY = new Day("THURSDAY", 4);
public static final Day FRIDAY = new Day("FRIDAY", 5);
public static final Day SATURDAY = new Day("SATURDAY", 6);
// 内部维护一个所有枚举值的数组,可通过 Day.values() 获取
private static final Day[] $VALUES = new Day[]{
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
};
// 枚举的构造方法是私有的,不允许外部创建新的实例
private Day(String name, int ordinal) {
super(name, ordinal);
// 调用父类 Enum 的构造方法
}
// 返回所有枚举值,等同于你调用 Day.values()
public static Day[] values() {
return $VALUES.clone();
// 返回一个副本,防止外部修改内部数组
}
// 根据名称返回对应的枚举实例,等同于你调用 Day.valueOf("MONDAY")
public static Day valueOf(String name) {
return Enum.valueOf(Day.class, name)
;
// 调用 Enum 类的静态方法
}
}

2、带有属性和方法的枚举

  • ​实例声明​:枚举实例是类级别的,必须在首行用逗号(,)分隔,若枚举类包含方法/属性,最后一个实例后需加分号(;)
  • 构造函数​:枚举的构造函数默认且只能是private​(即使不写修饰符),防止外部创建新实例
  • 属性限制​:属性通常声明为final(不强求),保证不可变性(枚举实例通常是单例且线程安全的)
// 订单状态枚举
public enum OrderStatus {
// 枚举实例(必须位于首行)
PENDING("待支付", 0),
PAID("已支付", 1),
SHIPPED("已发货", 2),
COMPLETED("已完成", 3);
// 枚举属性(通常为final)
private final String desc;
// 描述
private final int code;
// 状态码
// 构造函数(必须私有!,没有修饰符也表示private)
private OrderStatus(String desc, int code) {
this.desc = desc;
this.code = code;
}
// 根据 code状态码 直接获取对应的 desc描述
private static final Map<
Integer, OrderStatus> CODE_TO_ENUM_MAP = new HashMap<
>();
// 静态代码块:初始化映射
static {
for (OrderStatus status : OrderStatus.values()) {
CODE_TO_ENUM_MAP.put(status.getCode(), status);
}
}
public static String getDescByCode(int code) {
OrderStatus status = CODE_TO_ENUM_MAP.get(code);
if (status == null){
throw new IllegalArgumentException("无效的订单状态码: " + code);
}
return status.getDesc();
}
// Getter方法
public String getDesc() {
return desc;
}
public int getCode() {
return code;
}
}
  • 枚举实例本质是类的静态常量,通过类名直接访问
OrderStatus status = OrderStatus.PAID;
System.out.println(status.getDesc());
// 输出:已支付
System.out.println(status.getCode());
// 输出:1

编译器生成的大致等价代码:

public final class OrderStatus
extends Enum<
OrderStatus> {
// 静态的枚举实例,每个都是 OrderStatus 类型的静态 final 对象
public static final OrderStatus PENDING = new OrderStatus("PENDING", 0, "待支付", 0);
public static final OrderStatus PAID = new OrderStatus("PAID", 1, "已支付", 1);
public static final OrderStatus SHIPPED = new OrderStatus("SHIPPED", 2, "已发货", 2);
public static final OrderStatus COMPLETED = new OrderStatus("COMPLETED", 3, "已完成", 3);
// // 编译器生成的 values 数组,用于 values() 方法(按声明顺序)
private static final OrderStatus[] $VALUES = {
PENDING, PAID, SHIPPED, COMPLETED
};
// 自定义字段
private final String desc;
private final int code;
// 私有构造器,确保外部无法随意创建枚举实例
private OrderStatus(String name, int ordinal, String desc, int code) {
super(name, ordinal);
// 调用父类 Enum 的构造方法
this.desc = desc;
this.code = code;
}
// 自定义的code获取desc方法
private static final Map<
Integer, OrderStatus> CODE_TO_ENUM_MAP = new HashMap<
>();
static {
for (OrderStatus status : OrderStatus.values()) {
CODE_TO_ENUM_MAP.put(status.getCode(), status);
}
}
public static String getDescByCode(int code) {
OrderStatus status = CODE_TO_ENUM_MAP.get(code);
if (status == null){
throw new IllegalArgumentException("无效的订单状态码: " + code);
}
return status.getDesc();
}
// 自定义的getter方法
public String getDesc() {
return desc;
}
public int getCode() {
return code;
}
// 编译器生成的方法
public static OrderStatus[] values() {
return $VALUES.clone();
// 返回所有枚举值的拷贝
}
public static OrderStatus valueOf(String name) {
// 根据 name 查找对应的枚举实例,找不到则抛出 IllegalArgumentException
return Enum.valueOf(OrderStatus.class, name)
;
}
}

3、枚举的特点

  1. 枚举常量默认是public static final
  2. 枚举类隐式继承自java.lang.Enum
  3. 枚举不能被继承(因为已经继承了Enum
  4. 枚举构造函数总是私有的​(可以省略private关键字)
  5. 枚举可以添加字段方法构造函数

三、枚举方法和工具类

1、枚举的隐含方法和属性

所有枚举都隐式继承自java.lang.Enum,因此具有以下方法:

  1. name():返回枚举常量的名称(字符串)
  2. ordinal():返回枚举常量的序数(声明顺序,从0开始)
  3. toString():默认返回 name,可重写提供友好信息
  4. equals():比较两个枚举引用是否指向同一个对象(但通常直接用==更直观)
  5. hashCode():枚举的哈希码实现( 一般不用关心)
  6. compareTo(E o):比较两个枚举常量的序数(一般不用,除非需要排序)
  7. valueOf(String name):通过name字符串获取枚举常量(由编译器生成,不是Enum类的方法)
  8. values():返回枚举的所有常量(也是由编译器生成,不是Enum类的方法)

示例:

enum Color { RED, GREEN, BLUE
}
public class EnumDemo
{
public static void main(String[] args) {
Color c = Color.RED;
System.out.println(c.name());
// 输出: RED
System.out.println(c.ordinal());
// 输出: 0
System.out.println(c.toString());
// 输出: RED
// 使用values()方法
for (Color color : Color.values()) {
System.out.println(color);
}
// 使用valueOf()方法
Color red = Color.valueOf("RED");
System.out.println(red == Color.RED);
// 输出: true
}
}

2、工具类EnumSet/EnumMap

Java提供了专门用于枚举的集合实现,位于java.util包中:

  1. EnumSet - 高性能的枚举集合实现
  2. EnumMap - 键为枚举的高性能Map实现

EnumSet示例:

enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumSetDemo
{
public static void main(String[] args) {
// 创建一个包含所有Day枚举的EnumSet
EnumSet<
Day> allDays = EnumSet.allOf(Day.class)
;
System.out.println("所有天: " + allDays);
// 创建一个空的EnumSet
EnumSet<
Day> noDays = EnumSet.noneOf(Day.class)
;
noDays.add(Day.MONDAY);
noDays.add(Day.FRIDAY);
System.out.println("工作日: " + noDays);
// 创建一个包含范围的EnumSet
EnumSet<
Day> weekend = EnumSet.range(Day.SATURDAY, Day.SUNDAY);
System.out.println("周末: " + weekend);
// 创建一个补集
EnumSet<
Day> weekdays = EnumSet.complementOf(weekend);
System.out.println("工作日: " + weekdays);
}
}

EnumMap示例:

enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumMapDemo
{
public static void main(String[] args) {
EnumMap<
Day, String> activityMap = new EnumMap<
>(Day.class)
;
activityMap.put(Day.MONDAY, "上班");
activityMap.put(Day.TUESDAY, "上班");
activityMap.put(Day.WEDNESDAY, "上班");
activityMap.put(Day.THURSDAY, "上班");
activityMap.put(Day.FRIDAY, "上班");
activityMap.put(Day.SATURDAY, "休息");
activityMap.put(Day.SUNDAY, "休息");
for (Day day : Day.values()) {
System.out.println(day + ": " + activityMap.get(day));
}
}
}

四、枚举实现接口

枚举类可以实现一个或多个接口,为所有实例或单个实例提供统一行为。这在需要为不同枚举实例定义差异化逻辑时非常有用。

示例:定义支付策略接口:

// 支付策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 支付方式枚举(实现接口)
public enum PaymentMethod implements PaymentStrategy {
ALIPAY {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
},
WECHAT_PAY {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
}
},
BANK_CARD {
@Override
public void pay(double amount) {
System.out.println("使用银行卡支付:" + amount + "元");
}
};
}

使用接口方法:

PaymentMethod method = PaymentMethod.ALIPAY;
method.pay(199.9);
// 输出:使用支付宝支付:199.9元

五、枚举的单例模式

单例模式的核心是确保类仅一个实例,并提供全局访问点。枚举凭借JVM的类加载机制,天生具备线程安全、防反射攻击、防反序列化漏洞的特性,是《Effective Java》作者Joshua Bloch推荐的最佳实现方式。

1、为什么使用枚举实现单例?

示例:使用枚举实现单例模式

public enum Singleton {
INSTANCE;
// 这就是单例对象
// 可以添加单例的其他成员变量和方法
private int value;
public void doSomething() {
System.out.println("Singleton is doing something. Value = " + value);
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}

使用方法:

public class Main
{
public static void main(String[] args) {
// 获取单例对象
Singleton singleton = Singleton.INSTANCE;
singleton.setValue(42);
singleton.doSomething();
// 输出: Singleton is doing something. Value = 42
// 再次获取,仍然是同一个对象
Singleton anotherSingleton = Singleton.INSTANCE;
System.out.println(singleton == anotherSingleton);
// 输出: true
}
}

2、对比传统单例写法(如双重检查锁、静态内部类等)

实现方式线程安全防止反射攻击防止序列化破坏单例代码复杂度
枚举(推荐)
双重检查锁(需额外处理)⭐⭐⭐
静态内部类(需额外处理)⭐⭐
饿汉式(需额外处理)
懒汉式(非线程安全)

不需要兼容老代码,且追求最安全、最简洁的单例实现,那么使用枚举是最佳选择!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

传统开水壶升级智能水壶低成本开发方案WT588F02KD-32N

今天我们要聊的不是什么高深的半导体制造技术,而是一个更贴近我们日常生活的话题——如何让一个普普通通的便携式烧水壶变得"聪明伶俐",不仅能精准控温,还能开口"说话"告诉你水温。 相信经常出…

一般设计网站页面用什么软件餐饮官网建站模板

今天我们来探讨一个重要的话题&#xff1a;短时间内如何顺利通过 Java 面试&#xff1f; 在此之前&#xff0c;我正在精心编写一套完全面向小白的 Java 自学教程&#xff0c;我相信这套教程会非常适合正在努力提升的你。教程里面涵盖了丰富全面的编程教学内容、详细生动的视频…

做产品网站要备案吗贵阳市建设厅网站

凑算式B DEFA --- ------- 10C GHI&#xff08;如果显示有问题&#xff0c;可以参见【图1.jpg】&#xff09;这个算式中A~I代表1~9的数字&#xff0c;不同的字母代表不同的数字。比如&#xff1a;68/3952/714 就是一种解法&#xff0c;53/1972/486 是另一种解法。…

如何自己做购物网站wordpress linux 安装

娱乐行业的主要组织之一的美国影视演员协会&#xff08;SAG&#xff09;最近因云计算的需要选择Windows Azure解决方案。美国影视演员协会将他们的网站从基于Linux的服务器迁移到支持他们的最大年度事件——美国演员工会奖的Windows Azure上。 每年的年度颁奖典礼的到来标志着一…

基于MATLAB的经典车辆路径问题(VRP)求解方法详解

一、数学模型 经典VRP问题: 给定一个配送中心、多个客户点和若干车辆,要求规划车辆路径,使得所有客户需求被满足且总行驶距离/时间最小。核心约束包括:每个客户仅被访问一次 车辆从配送中心出发并返回 车辆容量限制…

kali复现arp欺骗

利用kali复现arp欺骗 本实验旨在帮助学习者理解 ARP 协议工作机制 以及 常见的ARP欺骗攻击原理与防护方法,仅限于 教学和实验环境 使用。实验过程中可能涉及到网络抓包、ARP表修改、ARP欺骗等操作,这些操作在实际生产…

VGGT: Visual Geometry Grounded Transformer

基于预训练模型的特征重建三维场景,预测多种三维信息。VGGT: Visual Geometry Grounded Transformer VGGT(CVPR25):基于预训练模型抽取特征,通过网络预测3D场景的多种信息。 代码仓库 注:笔者对3D场景重建相关领…

14种纯css3对话气泡样式代码

14种纯css3对话气泡样式代码Posted on 2025-09-26 16:01 且行且思 阅读(0) 评论(0) 收藏 举报<!DOCTYPE html> <html lang="en"><head><meta charset="utf-8" /><…

微信小程序使用地图map 实现定位和实时绘画轨迹

微信小程序使用地图map 实现定位和实时绘画轨迹1 文档官方文档api文档2 准备工作 2.1 注册开发者 1)进入腾讯位置服务官网地址2)注册注册号之后,这个key是需要用到的 2.2 开通地图服务 1)进入微信公众平台-账号设…

嵌入式入门,基于keil5用stm32寄存器和标准库实现LED流水灯

本文要实现的是控制STM32F103C8T6(后文简称STM32)初始化GPIO,并控制其引脚PA0(红色二极管)、PB5(蓝色二极管)和PC13(STM32自带的黄色LED)的高低电平实现LED流水灯。本文章采用的开发板是STM32F103C8T6,下载器是…

AI agent编程随记

ai编程(主要是cursor)确实大大提高了开发的效率,但是一旦在某个问题上无法解决陷入死循环确实很恼火。边用边记录用的经验吧。 1.一定要掌握代码的运行逻辑 最好由自己设计一套方法的运行逻辑由ai帮你快速实现,而不…

小人鱼的数学题 - Li

你这张图片显示的是一道平面解析几何题,题目主要内容如下: 在平面直角坐标系 $xOy$ 中,有一条直线 $y = kx - 3$(其中 $k \neq 0$)和抛物线 $y = -x^2$,它们相交于两点 $A$ 和 $B$,并且点 $A$ 在点 $B$ 的左侧。…

再见 Claude Code!玩转 CodeX CLI 的 16 个实用小技巧,效率拉满!!

大家好,我是R哥。 最近用上了 CodeX CLI,替代了 Claude Code,原因不多说,看这篇:再见 Claude Code,我选择了 Codex!真香!!今天,我再来分享一波我实战中积累的 CodeX CLI 实用小技巧,不管你是新手刚入坑,还…

【IEEE出版】第五届电气工程与机电一体化技术国际学术会议(ICEEMT 2025)

第五届电气工程与机电一体化技术国际学术会议(ICEEMT 2025)定于2025年10月17-19日在广东省深圳市隆重举行。【高层次嘉宾报告:欧洲科学院院士、IEEE Fellow、校长讲座教授、俄罗斯工程院外籍院士,分享研究成果,学…

网站开发前端后端小说网站排名怎么做

来源&#xff1a;科技部网站近日&#xff0c;国家科技部公布了2018年工程和材料领域国家重点实验室评估处理结果。本次64个实验室参加评估&#xff0c;其中工程领域共有43个&#xff0c;材料领域共有21个。评估结果显示&#xff0c;共有6个实验室要求整改&#xff0c;没有实验室…

网站备案承诺书怎么写网站正在建设中 html 模板

目录 1 继承的概念 2 继承的写法 3 子类继承父类的属性和方法 4 子类新增父类没有的属性和方法 5 子类重写父类的属性和方法 6 super超类的使用 7 多继承 1 继承的概念 继承是类与类之间的一种关系&#xff0c;子类继承父类。通过继承可以使得子类能够拥有父类的属性和方…

学习网站开发思路广东省医院建设协会网站首页

简介&#xff1a; 不管是核心大目标&#xff0c;还是O&#xff08;Objectives&#xff09;&#xff0c;或者北极星指标&#xff0c;奇妙等式等等&#xff0c;最后都需要核心组织协同方式来推动整个目标聚焦以及过程的落地。 作为产品经理人&#xff0c;相信很多人都遇到过以下的…

专注手机网站建设网页设计暑期班

教育 -现场生命急救知识与技能-章节资料考试资料-南昌大学【】 随堂测试 1、【多选题】急救医疗服务体系由哪几部分构成&#xff1f; A、院前急救 B、院内急诊 C、急危重症监护 D、康复治疗 参考资料【 】 随堂测试 1、【多选题】现场急救的目的有哪些&#xff1f; A、维持生命…

asp.net 网站的编译鄂州seo厂家

title: Android 项目新建问题总结 search: 2024-03-24 tags: “#Android 项目新建问题总结” Android 项目新建问题总结 一、gradle 项目每次都自动下载依赖包到C盘 背景&#xff1a;idea 首次打开一个 gradle 项目&#xff0c;都会在 C 盘下载项目所需的依赖包&#xff0c;但…

浏览器做单页网站项目互联网平面设计

目录 DP简介 01背包问题 采药(01背包例题) 完全背包 疯狂的采药(完全背包例题) 背包变式 装箱问题 砝码称重 质数拆分 优化思考 DP简介 全称Dynamic Programming即动态规划 DP算法是解决多阶段决策过程最优化问题的一种常用方法。 多阶段决策过程是指这样一类特…