发布于2026-07-10 阅读(0)
扫一扫,手机访问
在 Ja va 里,如果你想统计一个 BitSet 中到底有多少位被设为 true,cardinality() 就是最简单直接、效率也最高的那个方法。它不需要你写循环去遍历每一位,也不用引入什么第三方库,一行代码就能搞定。
这个方法内部做的是稀疏位计数优化——说白了就是分段查表加上 Long.bitCount。从时间复杂度上说,它接近 O(1),严格来讲是 O(有效字长数),但在绝大多数场景下完全可以当作常量来看。使用时有几个点需要留意:
BitSet(没调用过任何 set)返回 0,这很符合直觉。false,cardinality() 也只统计真正置位的那些位,不会傻乎乎地把整个范围扫一遍。trimToSize(),因为方法本身已经过滤掉了那些没被分配的 word 段。有的人可能会想着自己写个循环,用 nextSetBit() 或 get(i) 逐位统计。这么做不仅看着啰嗦,跑起来也慢得多。举个例子:
// ❌ 不推荐:O(n) 全量扫描,n 是最大索引+1int count = 0;for (int i = 0; i < bs.length(); i++) { if (bs.get(i)) count++;}// ✅ 推荐:O(实际置位块数),快一个数量级以上int count = bs.cardinality();尤其是当 BitSet 很稀疏的时候——比如只在索引 10000 和 200000 两处置了 true——cardinality() 几乎是瞬间出结果,而手动循环要老老实实检查 20 万次,差距不是一个量级。
BitSet.length() 返回的是「最高置位索引 + 1」,根本不是 true 的个数;它甚至可能大于实际内部容量(因为数组没压缩)。不少初学者会犯这样的错误:
bs.length() == bs.cardinality() —— 实际上前者是“逻辑长度”,后者才是“真值个数”,两码事。bs.size()(返回内部 long[] 数组的总容量)来估算 true 位数——这完全是两回事,返回值通常远大于实际置位数。bs.length() 返回 0,cardinality() 也返回 0,此时两者数值相等,但这个巧合不能推广到有数据的情况。真正需要记住的就是:统计 true 位数,只用 cardinality()。它不撒谎,不近似,JVM 对它做了深度优化。唯一需要操心的就是确保操作的是同一个 BitSet 实例,并且在并发写入时别漏掉同步。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8