BitSet 类在 Java 1.0 版本就已经被引入了。它是 Java 核心类库中的一部分,并且在后续的 Java 版本中一直存在并得到支持和优化。
BitSet 是一个表示 bit(二进制位)序列的整数集合。该集合可以根据整数 i 来设置第 i 个 bit 位的值。这使得集合操作非常高效。求并集、交集、补集只不过是简单的按位或、与、非运算。
默认情况下,集合中的所有位初始值都是 false。
每个位集都有一个当前大小,即位集当前使用的空间位数。请注意,大小与位集合的实现有关,因此可能会随着实现而改变。位集合的长度与位集合的逻辑长度有关,其定义与实现无关。
除非另有说明,否则向 BitSet 中的任何方法传递空参数都会导致 NullPointerException 异常。
在没有外部同步的情况下,BitSet 对于多线程使用是不安全的。
BitSet() 创建一个新的位集。
BitSet(int nbits) 创建一个比特集合,其初始大小足以明确表示索引范围在 0 到 nbits-1 之间的比特。
示例:
BitSet bitSet = new BitSet(); System.out.println(bitSet.isEmpty()); // true BitSet bitSet2 = new BitSet(8); System.out.println(bitSet2.size()); // 64
为什么 size() 返回的不是 8,而是 64 呢?调试一下:
其中,words 是一个 long 数组,如下图:
而 BITS_PER_WORD 是一个常量,如下图:
BITS_PER_WORD 的值是将 1 左移 6 位,0000 0001 左移 6 位为 0100 0000,即为 64。
Java7 添加了一些构造 BitSet 的方法,例如:
package com.hxstrive.jdk7.bitset; import java.util.BitSet; /** * BitSet 类 * @author hxstrive.com */ public class BitSetDemo2 { private static String show(BitSet bits) { StringBuilder result = new StringBuilder(); for (int i = 0; i < bits.size(); ++i) { result.append(bits.get(i) ? "1" : "0"); } return result.toString(); } public static void main(String[] args) { // 使用 long 初始化 // 6 的二进制为 0b0110,因此下标为 1 和 2 的位为 true BitSet base = BitSet.valueOf(new long[]{ 6L }); System.out.println(show(base)); System.out.println(base); // 0110000000000000000000000000000000000000000000000000000000000000 // {1, 2} // 注意:BitSet 的 toString() 方法将返回位为 true 的下标值 // 使用 byte 初始化 // 1010 1100 0010 1000 byte[] bytes = { (byte)0b10101100, (byte)0b00101000 }; BitSet primes = BitSet.valueOf(bytes); System.out.println(show(primes)); System.out.println(primes); // 0011010100010100000000000000000000000000000000000000000000000000 // 00110101 00010100 BitSet中的字节顺序 // 10101100 00101000 真实的字节顺序 // {2, 3, 5, 7, 11, 13} } }
根据上面示例可知,在 BitSet 中,存放字节的顺序和实际表示的字节顺序相反,例如:
(1)假如存在如下两个字节:
10101100
00101000
(2)在 BitSet 中存放如下:
a、先存放 10101100,将地位存放在高位,高位存放在地位,存放结果为:00110101
b、再次存放 00101000,存放结果为:00010100
(3)最后 BitSet 中的内容为:
00110101 00010100
如果要获得对应的引用类型,则调用方法为 toByteArray 和 toLongArray。
package com.hxstrive.jdk7.bitset; import java.util.Arrays; import java.util.BitSet; /** * BitSet 类 * @author hxstrive.com */ public class BitSetDemo3 { public static void main(String[] args) { // 使用 long 初始化 BitSet base = BitSet.valueOf(new long[]{ 6L }); System.out.println(Arrays.toString(base.toLongArray())); //[6] // 使用 byte 初始化 byte[] bytes = { (byte)0b10101100, (byte)0b00101000 }; BitSet primes = BitSet.valueOf(bytes); System.out.println(Arrays.toString(primes.toByteArray())); //[-84, 40] } }
注意:在 Java8 中,BitSet 提供了一个可以返回 IntStream 的 stream 方法。例如:
package com.hxstrive.jdk8.bitset; import java.util.BitSet; import java.util.stream.IntStream; /** * BitSet 类 * @author hxstrive.com */ public class BitSetDemo1 { public static void main(String[] args) { BitSet base = BitSet.valueOf(new long[]{ 0b0110_0101L }); IntStream stream = base.stream(); stream.forEach(System.out::print); //结果: //0256 } }
以下是 BitSet 类的一些常用方法:
void set(int bitIndex):将指定索引位置的位设置为 true,即位的值为 1。
void clear(int bitIndex):将指定索引位置的位设置为 false,即位的值为 0。
void clear():将 BitSet 中的所有位设置为 false。
boolean get(int bitIndex):获取指定索引位置的位的值。
int cardinality():返回 BitSet 中设置为 true 的位的数量。
int nextSetBit(int fromIndex):返回指定索引位置(fromIndex)之后第一个设置为 true 的位的索引。如果没有这样的位,则返回 -1。
int previousSetBit(int fromIndex):返回指定索引位置(fromIndex)之前第一个设置为 true 的位的索引。如果没有这样的位,则返回 -1。
void and(BitSet set):执行当前 BitSet 与给定 BitSet 的逻辑与操作。
void or(BitSet set):执行当前 BitSet 与给定 BitSet 的逻辑或操作。
void xor(BitSet set):执行当前 BitSet 与给定 BitSet 的逻辑异或操作。
示例:
package com.hxstrive.jdk7.bitset; import java.util.BitSet; /** * BitSet 类 * @author hxstrive.com */ public class BitSetDemo4 { public static void main(String[] args) { BitSet bitSet1 = new BitSet(); BitSet bitSet2 = new BitSet(); bitSet1.set(0); // 将下标为0的位设置为1,即true bitSet1.set(2); bitSet1.set(4); bitSet2.set(1); bitSet2.set(2); bitSet2.set(3); System.out.println("BitSet1: " + bitSet1); //BitSet1: {0, 2, 4} System.out.println("BitSet2: " + bitSet2); //BitSet2: {1, 2, 3} // 执行逻辑与操作 //BitSet1: {0, 2, 4} //BitSet2: {1, 2, 3} bitSet1.and(bitSet2); System.out.println("After AND operation: " + bitSet1); //After AND operation: {2} // 重新设置 bitSet1 bitSet1.set(0); bitSet1.set(2); bitSet1.set(4); System.out.println("bitSet1:" + bitSet1); //bitSet1:{0, 2, 4} // 执行逻辑或操作 //BitSet1: {0, 2, 4} //BitSet2: {1, 2, 3} bitSet1.or(bitSet2); System.out.println("After OR operation: " + bitSet1); //After OR operation: {0, 1, 2, 3, 4} // 重新设置 bitSet1 bitSet1.set(0); bitSet1.set(2); bitSet1.set(4); System.out.println("bitSet1:" + bitSet1); //bitSet1:{0, 2, 4} // 执行逻辑异或操作 //BitSet1: {0, 2, 4} //BitSet2: {1, 2, 3} show(bitSet1); //1111100000000000000000000000000000000000000000000000000000000000 show(bitSet2); //0111000000000000000000000000000000000000000000000000000000000000 bitSet1.xor(bitSet2); System.out.println("After XOR operation: " + bitSet1); //After XOR operation: {0, 4} } private static void show(BitSet bitSet) { for(int i = 0; i < bitSet.size(); i++) { System.out.print(bitSet.get(i) ? "1" : "0"); } System.out.println(); } }