news 2026/6/26 16:37:56

java枚举

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java枚举

什么是枚举?

用一句话概括:枚举就是“固定选项的集合”


为什么需要枚举?

  • 类型安全:编译期就能发现错误,不会传入非法值
  • 可读性强OrderStatus.PAID"1""paid"清晰得多
  • 防止非法值:方法参数限定了取值范围,调用方无法随意传值

基础篇:最简单的枚举

publicenumOrderStatus{CREATED,// 已创建PAID,// 已支付SHIPPED,// 已发货COMPLETED// 已完成}

枚举值之间用逗号隔开,最后一个可以有分号。

使用方式:

publicclassOrder{privateOrderStatusstatus;// ✅ 类型安全publicvoidpay(){if(status==OrderStatus.CREATED){status=OrderStatus.PAID;}}}

进阶篇:带字段和方法的枚举

实际项目中,枚举通常需要携带额外属性(如编码、描述等):

publicenumOrderStatus{CREATED("0","已创建"),PAID("1","已支付"),SHIPPED("2","已发货"),COMPLETED("3","已完成");// 成员变量privatefinalStringcode;// 用于数据库存储privatefinalStringdesc;// 用于前端展示// 构造方法(必须是 private)privateOrderStatus(Stringcode,Stringdesc){this.code=code;this.desc=desc;}// getter 方法publicStringgetCode(){returncode;}publicStringgetDesc(){returndesc;}}

关键点:

  • 构造方法必须是private,这是枚举的语法规定
  • 字段推荐用final,枚举值应该是不可变的(后面会重点讲)

枚举的内置方法

Java 为所有枚举自动提供了几个实用方法:

// 1. name():返回枚举常量的名称OrderStatus.PAID.name();// 返回 "PAID"// 2. ordinal():返回声明顺序(从 0 开始)OrderStatus.CREATED.ordinal();// 返回 0OrderStatus.PAID.ordinal();// 返回 1// 3. valueOf(String):字符串转枚举OrderStatusstatus=OrderStatus.valueOf("PAID");// 相当于 OrderStatus.PAID// 4. values():获取所有枚举常量for(OrderStatusstatus:OrderStatus.values()){System.out.println(status);}// 输出:CREATED PAID SHIPPED COMPLETED

应用场景

1. 在实体类中作为字段

publicclassOrderEntity{privateStringorderId;privateStringuserId;privateOrderStatusstatus;// ✅ 用枚举类型// 判断订单是否可支付publicbooleancanPay(){returnstatus==OrderStatus.CREATED;}}

2. 作为方法的参数或返回值

publicclassOrderService{// 参数限制:只能传 OrderStatus 中定义的值publicvoidupdateStatus(StringorderId,OrderStatusnewStatus){// 业务逻辑...}}

3. 配合 switch 做多分支逻辑

publicStringgetStatusDesc(OrderStatusstatus){switch(status){caseCREATED:return"订单已创建,等待支付";casePAID:return"已支付,正在准备发货";caseSHIPPED:return"已发货,请注意查收";caseCOMPLETED:return"订单已完成";default:return"未知状态";// 理论上不执行,保留健壮性}}

Spring Boot 中的枚举映射(@Enumerated)

在 Spring Boot + JPA 项目中,枚举需要存到数据库,这时要用@Enumerated注解:

@Entity@Table(name="orders")publicclassOrder{@IdprivateStringorderId;privateStringuserId;// 方式一:存枚举名称(字符串)@Enumerated(EnumType.STRING)privateOrderStatusstatus;// 存 "PAID" 到数据库// 方式二:存枚举序号(数字)⚠️ 不推荐!// @Enumerated(EnumType.ORDINAL)// private OrderStatus status; // 存 0, 1, 2... 到数据库}

EnumType.STRINGvsEnumType.ORDINAL

对比维度EnumType.STRINGEnumType.ORDINAL
存什么枚举名称(如"PAID"序号(如1
可读性数据库里一眼看懂需要查文档才知道1代表什么
顺序依赖不依赖声明顺序❌ 新增枚举插在中间会乱套
推荐✅ 推荐使用❌ 不推荐,有坑

配合 MyBatis 使用(另一种方式)

如果用 MyBatis,可以自定义 TypeHandler 或直接用code字段存:

// 存 code 到数据库order.setStatus(OrderStatus.PAID.getCode());// 存 "1"

枚举 vs 结构体(对比)

初学时有个对比会清晰一些。

核心区别在于"实例数量":

对比维度枚举结构体
实例数量固定有限(编译期确定)无限(运行时随意 new)
能否伪造不能(类型安全)可以(绕开常量定义)
适用场景固定选项(状态、类型等)数据容器(用户、商品等)

一句话记住:枚举是"选一个",结构体是"装一堆"。


枚举必须不可变!

枚举值是全局单例的,这意味着如果你修改了某个枚举值的属性,会影响所有使用它的地方。

❌ 反面示例(在CSDN上看到的错误示例)

publicenumRole{WARRIOR("战士",100),// ❌ 没有 final 的字段MAGE("法师",80);privateStringname;privateinthp;privateRole(Stringname,inthp){this.name=name;this.hp=hp;}publicvoidsetHp(inthp){// ❌ 提供了 setter!this.hp=hp;}}
// 使用方Role.MAGE.setHp(50);// ❌ 修改了枚举值本身System.out.println(Role.MAGE.getHp());// 输出 50,不是 80 了!

问题:所有法师的血量都被改成了 50!

✅ 正确写法

publicenumRole{WARRIOR("战士",100),MAGE("法师",80);privatefinalStringname;// ✅ finalprivatefinalinthp;// ✅ finalprivateRole(Stringname,inthp){this.name=name;this.hp=hp;}publicStringgetName(){returnname;}publicintgetHp(){returnhp;}// ✅ 没有 setter!}

如果每个玩家的血量要独立变化怎么办?

血量应该存在玩家对象里,而不是枚举里:

publicclassPlayer{privateRolerole;// 职业(模板)privateintcurrentHp;// 当前血量(实例状态)privateintcurrentAttack;// 当前攻击力privateintcurrentDefense;// 当前防御力publicPlayer(Rolerole){this.role=role;this.currentHp=role.getHp();// 从模板复制this.currentAttack=role.getAttack();this.currentDefense=role.getDefense();}publicvoidattack(Playertarget){intdamage=this.currentAttack-target.currentDefense;if(damage>0){target.currentHp-=damage;// ✅ 只修改玩家的血量}}}

总结

核心要点说明
枚举是什么固定选项的集合,用于表示有限的、不变的值
为什么用枚举类型安全、可读性强、防止非法值
基本语法public enum Xxx { A, B, C }
带字段写法私有构造方法 +final字段 + getter
Spring Boot 映射使用@Enumerated(EnumType.STRING)存到数据库
与结构体区别枚举实例数固定,结构体可无限创建
最重要原则枚举必须不可变,所有字段都应该是final
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 16:37:05

高精度GNSS工程控制网数据处理与精度评估:GAMIT/GLOBK系统实践

随着GNSS导航定位技术在不同领域的广泛应用和技术更新的飞速发展,在大型工程项目的设计、施工、运行和管理各个阶段对工程测量提出了更高的要求,许多测绘、勘测、规划、市政、交通、铁道、水利水电、建筑、矿山、道桥、国土资源、气象、地震等行业部门在…

作者头像 李华
网站建设 2026/6/26 16:36:04

网络简要学习

设备 A 想把数据发给设备 B,先判断 B 是不是“本地人”。如果是同一个子网,就直接找 B;如果不是,就把数据交给网关,让网关继续转发。IP 用来标识最终要找谁。MAC 用来标识下一跳发给谁。子网掩码用来判断目标是不是本地…

作者头像 李华
网站建设 2026/6/26 16:35:13

星载与地基InSAR技术原理、方法及SARscape数据处理全流程解析

合成孔径雷达干涉测量(Interferometric Synthetic Aperture Radar, InSAR)技术作为一种新兴的主动式微波遥感技术,凭借其可以穿过大气层,全天时、全天候获取监测目标的形变信息等特性,已在地表形变监测、DEM生成、滑坡…

作者头像 李华
网站建设 2026/6/26 16:33:29

思源宋体完整实战指南:7种字重免费打造专业中文排版

思源宋体完整实战指南:7种字重免费打造专业中文排版 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为中文排版设计而烦恼吗?商业字体太贵,免费…

作者头像 李华
网站建设 2026/6/26 16:31:45

许可证利用率优化怎么做:企业先别急着加预算,先看使用行为和调配方式

摘要如果企业在没有完成使用分析的前提下就直接增购,往往会出现预算增加但利用率依旧偏低的情况。本文从高峰并发、模块结构、低效占用和历史趋势四个维度,分析为什么多数企业更适合先优化,再判断是否需要增购。 很多企业已经意识到一个现实&…

作者头像 李华