EnumMap 比 HashMap 快,因其底层用 Object[] 数组按枚举 ordinal() 直接索引,省去哈希计算、冲突处理与装箱开销,get/put 均为 O(1);实测小数据量下快 2–3 倍。

EnumMap 为什么比 HashMap 快
EnumMap 内部不使用哈希表,而是用一个数组直接按枚举的 ordinal() 值索引——每个枚举常量在声明顺序中固定位置,ordinal() 就是它的下标。这意味着 get() 和 put() 都是 O(1) 数组访问,无哈希计算、无碰撞处理、无装箱开销。
常见误用是拿 HashMap<someenum v></someenum> 替代 EnumMap<someenum v></someenum>,尤其在高频读写场景(如状态机跳转、配置映射),性能差距可达 2–3 倍。
必须用枚举类作为键,且不能是 null 或非声明值
EnumMap 构造时必须传入具体的枚举类,例如 new EnumMap<color string>(Color.class)</color>。它会在内部创建长度为 Color.values().length 的数组,所有操作都依赖这个静态结构。
以下情况会抛异常:
- 传入
null作为 key →NullPointerException - 传入非该枚举类的实例(比如子类或反射构造的非法实例)→
ClassCastException - 运行时动态生成的枚举值(JVM 不允许)→ 实际不会发生,但别试图绕过类型检查
注意:EnumMap 不支持泛型通配符构造,比如 new EnumMap extends Enum, V>(...) 是编译不过的。
keySet() / values() / entrySet() 返回的是“视图”,不是副本
EnumMap 的三个集合视图是弱一致性快照:它们不阻塞写操作,也不保证迭代时看到最新修改。更关键的是——它们不支持 remove() 以外的结构性修改:
-
keySet().add(...)→UnsupportedOperationException -
values().clear()→ 同样抛异常 - 但
keySet().remove(color)是合法的,等价于map.remove(color)
如果需要可变集合,得显式复制:new ArrayList(map.keySet()),否则迭代中混用 put() 和 keySet().iterator() 可能跳过新 entry 或重复遍历旧 entry。
初始化时建议预设容量?不,EnumMap 不需要
EnumMap 没有容量参数,也不接受初始容量构造器。它的“容量”完全由枚举类的 values().length 决定,且不可变。试图用 new EnumMap(Color.class) 之后再 put 超出枚举范围的 key 是编译期就拦住的(类型系统保障)。
唯一要注意的是:如果枚举类未来新增常量,旧版 EnumMap 实例不会自动扩容——它仍只认加载时已知的 values(),新增常量的 ordinal() 在旧 JVM 中尚未存在,自然无法被 map 索引到。所以服务长期运行时,枚举变更需重启或热替换支持。


















