bitset 是 java 中以 1 bit 存储布尔值的紧凑工具,专用于整数索引的二值状态管理;支持高效位运算与动态扩容,但需注意索引越界静默返回 false、线程不安全及内存估算等关键细节。

Java 中 BitSet 是处理布尔状态最紧凑的原生工具,核心在于用 1 bit 存一个 true/false,而不是 boolean[] 那样占 1 字节。它不适用于存对象或字符串,专为“整数索引 + 二值状态”场景设计,比如用户 ID 是否在线、日志序号是否已处理、节点是否被访问过。
创建与基础操作:别踩 set/clear/get 的坑
BitSet 默认初始容量 64 位,支持动态扩容,但索引必须是非负整数:
- 创建方式:`new BitSet()`(默认)或 `new BitSet(5000000)`(预设上限,避免频繁扩容)
- 设置位:`bitSet.set(123)` 等价于 `set(123, true)`;清零要用 `set(123, false)` 或更清晰的 `clear(123)`
- 读取位:`get(123)` 越界不报错,直接返回 false——这是静默陷阱,务必确保索引在合理范围内
- 翻转位:`flip(123)` 只翻单个位;全翻要用 `flip(0, bitSet.length())`,注意是左闭右开区间
批量位运算:交并差异或一次到位
BitSet 天然支持集合级逻辑运算,底层对 long 数组批量执行 CPU 位指令,百万级元素运算比遍历 ArrayList 快一个数量级以上:
OpenJDK 24 Windows x64 官方参考实现(24+36),适合 Windows 环境进行 Java 开发、编译、运行和版本兼容性验证。
- 交集:`a.and(b)` → a 变成 a ∩ b(原地修改)
- 并集:`a.or(b)` → a 变成 a ∪ b
- 差集:`a.andNot(b)` → a 变成 a − b(属于 a 但不属于 b)
- 异或:`a.xor(b)` → a 变成对称差集(仅在 a 或 b 中出现)
- 如需保留原始 BitSet,务必先 clone:`BitSet result = (BitSet) a.clone(); result.and(b);`
内存与性能关键细节
BitSet 省空间的本质是 long[] 存储(每个 long 支撑 64 位),但实际使用中容易忽略几个硬约束:
- 内存估算:若最大索引是 N,真实内存 ≈ ((N + 64) / 64) × 8 字节(向上取整到 long 个数);例如标记 0~4999999 的存在性,约需 625 KB
- length() ≠ 容量:`length()` 返回最高 set 位索引 + 1(逻辑长度);`size()` 才是内部 long 数组长度 × 64(分配总量)
- 线程不安全:所有 and/or/xor 方法都非同步,多线程共享时必须加锁或每次 clone 后操作
- 序列化注意:默认序列化整个 words 数组,高位空 long 也会写入,体积可能远超有效数据;高密度场景建议自定义压缩
典型适用与避坑提醒
它不是万能集合,只在特定条件下优势明显:
- 适合:ID 连续的用户签到标记、质数筛、图算法中 visited 数组、布隆过滤器底层存储
- 不适合:存字符串/对象、ID 极其稀疏(如只有 1 和 999999999)、需要插入顺序遍历、替代 HashSet 做通用去重
- 常见误用:传小初始容量却 set 大索引(如 `new BitSet(10); set(1000000)`),导致隐式扩容浪费;把 `get()` 静默返回 false 当作“安全兜底”,实则掩盖越界错误
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










