enumset 的集合运算快,是因为它将 union、retainall、removeall 直接映射为单条位运算指令(|、&、& ~),无需哈希计算或遍历,时间复杂度恒为 o(1);而 hashset 需逐元素哈希查找,开销随集合大小增长。

EnumSet 的集合运算快,是因为它把 add/remove/contains 全部转成位运算,不是靠循环或哈希表遍历。只要枚举常量 ≤64 个,底层就用单个 long 存,|、&、& ~ 直接搞定并集、交集、差集。
为什么 EnumSet 的 union/retainAll 比 HashSet 快得多
HashSet 做 addAll 或 retainAll 需要逐个调用 add 或检查每个元素是否在另一集合中,涉及哈希计算、桶查找、可能的扩容。EnumSet 完全不走这套逻辑:
-
union就是两个long值按位或:set1.bits | set2.bits -
retainAll(交集)是按位与:set1.bits & set2.bits -
removeAll(差集)是按位与非:set1.bits & ~set2.bits - 哪怕集合里只含 1 个或 3 个枚举值,运算开销也和含 60 个一样——都是单条 CPU 指令
EnumSet.range() 和 complementOf() 的隐含陷阱
range 看似方便,但要求两个参数在枚举中**声明顺序连续**,否则行为未定义(比如 Day.MONDAY 到 Day.FRIDAY 可以,但跨过中间值乱序定义的枚举会漏掉或抛异常)。complementOf() 更容易踩坑:
- 它返回的是“当前 enum 所有常量中,不在原集合里的那些”,不是“全局补集”
- 如果后续往 enum 里新增常量,所有已存在的
complementOf()结果会自动包含它——这在配置热更新时可能引发权限扩大 - 迭代这个补集,会遍历整个 enum(哪怕只排除 1 个),当 enum 有上百个值时,
for (E e : complement)效率骤降
EnumSet.copyOf() 和类型安全边界
别用 new EnumSet——它是抽象类,编译就报错。要用静态工厂方法,且第一个参数必须是具体枚举类的 Class 对象:
-
EnumSet.copyOf(someCollection)要求someCollection里每个元素都属于同一枚举类型,否则运行时报ClassCastException - 从 JSON 或 DB 读字符串再转 enum 时,
MyEnum.valueOf(str)失败会抛IllegalArgumentException,必须提前校验,不能直接塞进of()或copyOf() - 传
EnumSet.of(A, B)给期望Set<object></object>的方法没问题,但传给只接受HashSet参数的方法会编译失败
真正要注意的不是“怎么写对”,而是“什么时候不该用”:枚举值超过 64 个时,EnumSet 自动切到 long[],位运算仍快,但内存局部性下降;enum 类型未来大概率要频繁增删常量时,complementOf() 和 range() 的语义稳定性就得重新评估。










