EnumMap 用枚举 ordinal 作数组索引实现 O(1) 存取,构造时必须传入枚举类以初始化固定长度数组,键不可为 null 且须属指定枚举类型,遍历顺序即枚举声明顺序。

Java 中 EnumMap 高效存储枚举键,核心在于它**不用哈希,而用数组下标直访**——把枚举的 ordinal() 当作数组索引,一次内存读取就完成存取,跳过了哈希计算、扩容、碰撞处理和装箱开销。
必须显式传入枚举类初始化
EnumMap 无法靠泛型推断键类型,构造时必须指定具体枚举类:
- ✅ 正确:
new EnumMap<Status, String>(Status.class) - ❌ 错误:
new EnumMap<>()(编译失败)或传错类(如Object.class)
这一步触发内部数组创建:长度 = Status.values().length,每个位置对应一个枚举常量的 ordinal 值。
底层是固定长度 Object[] 数组
它不维护哈希桶、链表或红黑树,只有一块连续内存:
立即学习“Java免费学习笔记(深入)”;
-
put(Status.DONE, "已完成")→ 写入table[2](假设DONE.ordinal() == 2) -
get(Status.DONE)→ 直接读table[2],无分支判断、无循环查找 - 哪怕只存 3 个键,100 个常量的枚举也会分配 100 元素数组
键值语义与安全边界
高效的前提是严格约束:
- 键绝不能为
null,否则立即抛NullPointerException - 键必须属于构造时传入的枚举类,非法实例(如反射伪造)会触发
ClassCastException - value 可为
null,但需用containsKey(key)判断存在性,而非依赖get(key) == null - 遍历顺序天然等于枚举声明顺序(
values()顺序),无需额外排序
适合场景与避坑提醒
不是所有 Map 场景都该换,关键看是否匹配其设计契约:
- ✅ 推荐用:状态码描述映射、订单状态→操作集合、权限开关配置、策略分发表
- ❌ 慎用:枚举常量超几百且稀疏使用;枚举需运行时动态扩展(如插件机制);多线程高频并发写入(需手动同步)
- ⚠️ 注意:不支持泛型通配符(如
EnumMap<? extends Enum, V>编译不通过);服务长期运行中新增枚举常量,需重启或热替换支持


















