enumset用位向量实现,每个枚举常量按声明顺序分配唯一比特位,≤64个时用单个long表示,>64个时用long数组,所有操作均为o(1)位运算。

EnumSet 用位向量(Bitmask)实现高性能,核心在于每个枚举常量对应一个唯一 bit 位,集合状态用一个 long 或 int 整数紧凑表示,所有操作都是位运算,几乎没有对象分配和循环遍历。
位向量如何映射枚举常量
EnumSet 要求枚举类的常量在编译期确定且顺序固定(即声明顺序)。它按声明顺序给每个常量分配索引:第 0 个常量对应 bit 0(值为 1L
- 例如 enum Color { RED, GREEN, BLUE } → RED=bit0(1)、GREEN=bit1(2)、BLUE=bit2(4)
- 集合 {RED, BLUE} 的位向量就是 1 | 4 = 5(二进制 101)
- 内部字段通常是 long elements(小枚举)或 long[] elements(大枚举)
关键操作全靠位运算
add、contains、remove、retainAll 等方法不依赖循环或哈希查找,直接操作位:
- contains(E e):(elements & (1L
- add(E e):elements |= (1L
- remove(E e):elements &= ~(1L
-
addAll(EnumSet
other) :this.elements |= other.elements
这些是 CPU 级别单指令操作,O(1) 时间复杂度,无内存分配,缓存友好。
为什么不用 HashSet 或 TreeSet
对比其他 Set 实现:
- HashSet:每个元素包装成 Entry 对象,哈希计算+链表/红黑树查找,有装箱开销和 GC 压力
- TreeSet:基于红黑树,O(log n) 查找,还要实现 Comparable 或传 Comparator
- EnumSet:零对象创建(除集合本身),位运算一次完成,空间仅需 ⌈n/64⌉ 个 long,内存占用最小
尤其在频繁增删查、枚举类型固定且数量少时,EnumSet 性能优势明显。
使用限制与注意事项
位向量设计带来高效,也带来约束:
- 只能用于 enum 类型,且必须是同一枚举类的实例
- 枚举常量数超过 64 时,内部转为 long[],但仍是位运算,只是多一次数组索引
- 不支持 null 元素(枚举本身就不允许 null)
- 所有 EnumSet 实例都是 mutable,且非线程安全,多线程需外部同步
创建推荐用静态工厂方法(如 EnumSet.of()、EnumSet.range()),它们会根据参数数量自动选择最优实现(RegularEnumSet 或 JumboEnumSet)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











