EnumMap 快是因为直接用枚举ordinal值作数组下标,省去哈希计算、冲突处理与节点遍历;底层用Object[]存储,get操作仅需一次整数运算加一次数组访问,严格O(1)。

EnumMap 的快速定位不依赖哈希,靠的是枚举自身的序号(ordinal)直接当数组下标用。
枚举 ordinal 天然就是数组索引
每个枚举常量在编译时就固定了声明顺序,ordinal() 返回从 0 开始的连续整数。比如:
-
Color.RED是第一个声明的 →ordinal() == 0 -
Color.GREEN是第二个 →ordinal() == 1 -
Color.BLUE是第三个 →ordinal() == 2
EnumMap 构造时就调用 Color.class.getEnumConstants() 拿到全部常量,据此创建长度为 3 的 Object[] vals 数组。存取时直接按序号读写:
int index = key.ordinal(); // 不算 hash,不比较 key return (V) vals[index]; // 一次内存访问完成
内部双数组结构保障零冲突
EnumMap 底层不是单数组,而是两个配套数组:
立即学习“Java免费学习笔记(深入)”;
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
-
K[] keyUniverse:存所有枚举常量(按声明顺序),长度 = 枚举总数 -
Object[] vals:存对应 value,索引与keyUniverse严格对齐
因为每个枚举值在 keyUniverse 中位置唯一且固定,vals 就不会出现“不同 key 映射到同一位置”的情况——根本不存在哈希冲突的土壤。
和 HashMap 的关键区别在哪
HashMap 查一个 key 要走完整链路:算 hashCode() → 取模定位桶 → 遍历链表或红黑树 → 调 equals() 比较;而 EnumMap 省掉了全部这些步骤:
- 不调
hashCode()(枚举对象不用计算) - 不调
equals()(ordinal 唯一,无需比内容) - 不建 Node 对象(没链表/树节点开销)
- 不扩容、不重哈希(数组长度编译期已定死)
整个操作就是一次整数运算加一次数组寻址,CPU 缓存友好,实测吞吐量通常是 HashMap 的 2–3 倍。
使用时要注意的硬约束
这种极致效率是以类型安全为前提换来的:
- 键必须是枚举类型(泛型限定
K extends Enum<k></k>) - 不允许 null 键(枚举实例不可能为 null)
- 不支持运行时新增枚举常量(已有 EnumMap 不会自动扩容)
- 遍历顺序固定为枚举声明顺序,不是插入顺序
只要键确实是枚举,用 EnumMap 就是把编译期已知的信息直接“翻译”成最简运行时操作,快得理所当然。

















