EnumMap 是以枚举 ordinal 为下标的数组实现,O(1) 时间复杂度、无哈希冲突、内存占用少 40%;必须显式传入枚举类构造,键仅限该枚举实例,遍历按声明顺序,视图只读,多线程需同步。

直接用枚举常量作 Key,EnumMap 就是最佳选择——它不走哈希,而是把枚举的 ordinal() 当数组下标,get/put 全是 O(1) 直接访问,没装箱、没冲突、内存占用比 HashMap 少约 40%。
必须显式传入枚举类构造
EnumMap 不允许类型推断或泛型擦除,构造时必须写明具体枚举类:
- ✅ 正确:
new EnumMap<HttpStatus, String>(HttpStatus.class) - ❌ 编译失败:
new EnumMap<HttpStatus, String>()(缺少 class 参数) - ❌ 运行时报错:
new EnumMap(clazz)(若clazz是反射获取且非准确枚举类字节码)
这一步决定了内部数组长度:它等于 HttpStatus.values().length,所有操作都依赖这个静态结构,后续无法扩容或变更。
键只能是该枚举的有效实例
EnumMap 对键类型极其严格,只认构造时指定的那个枚举类的合法常量:
立即学习“Java免费学习笔记(深入)”;
-
map.put(null, "x")→ 立即抛NullPointerException -
map.put(OtherEnum.OK, "x")→ 抛ClassCastException - 允许 value 为
null,但get(key) == null无法区分“键不存在”还是“值设为 null”
判断存在性请用 containsKey(key);需要惰性初始化可用 computeIfAbsent(key, func)。
遍历天然有序,但别当成业务契约
迭代顺序严格按枚举声明顺序(即 ordinal() 升序),这是数组下标遍历的自然结果:
- 适合生成状态流转说明、配置下拉列表等需稳定顺序的场景
- 不要隐含“第一个就是默认值”这类逻辑——在枚举开头新增常量会直接破坏它
- 不支持
Comparator,不能替代TreeMap做自定义排序
集合视图是只读快照,修改要小心
keySet()、entrySet()、values() 返回的是视图,不是副本:
-
keySet().add(...)或values().clear()→ 抛UnsupportedOperationException -
keySet().remove(key)是合法的,等价于map.remove(key) - 如需可变集合,得显式复制:
new ArrayList(map.keySet()) - 多线程写入需手动同步,它本身线程不安全



















