我们已经了解了BitMap,在Java中已经提供了BitMap的实现,即java.util.BitSet类。
BitSet内部维护了一个long型的数组,long的大小是8 Byte,即 64 位,所以每个元素可以存储64个数字:
/**
* The internal field corresponding to the serialField "bits".
*/
private long[] words;
存储元素:
/**
* Sets the bit at the specified index to {@code true}.
*
* @param bitIndex a bit index
* @throws IndexOutOfBoundsException if the specified index is negative
* @since JDK1.0
*/
public void set(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
int wordIndex = wordIndex(bitIndex);
expandTo(wordIndex);
words[wordIndex] |= (1L << bitIndex); // Restores invariants
checkInvariants();
}
/**
* Given a bit index, return word index containing it.
*/
private static int wordIndex(int bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD;
}
/**
* Ensures that the BitSet can accommodate a given wordIndex,
* temporarily violating the invariants. The caller must
* restore the invariants before returning to the user,
* possibly using recalculateWordsInUse().
* @param wordIndex the index to be accommodated.
*/
private void expandTo(int wordIndex) {
int wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
ensureCapacity(wordsRequired);
wordsInUse = wordsRequired;
}
}
/**
* Every public method must preserve these invariants.
*/
private void checkInvariants() {
assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
assert(wordsInUse >= 0 && wordsInUse <= words.length);
assert(wordsInUse == words.length || words[wordsInUse] == 0);
}
假设要存储数据3,首先通过wordIndex(bitIndex);计算出3对应的数组的位置,这里是右移6位实现(相当于3 / 64),结果是0,即3对应的位置在数组的第0个元素。接下来expandTo(wordIndex);方法确保 BitSet 可以容纳给定的 wordIndex,即如果超过容量,会对数组进行扩容。然后 words[wordIndex] |= (1L << bitIndex);将数字3对应bit位置为1(将1左移3位,然后与原值进行 | 运算)。最后checkInvariants();进行一些校验。假设BitSet以前没有存储任何数据,经过以上操作后,数组第0位的数据应该是8(1000)。
接下,假设要存储数据1,还是按照以上步骤,最后的结果是数组的第0位对应的数据是10(1010)。
什么意思呢?因为是按位存储数据,从右往左,1010的第0位代表数字0,此时是0,表示0不存在;第1位表示数字1,此时是1,表示1存在。
获取元素:
/**
* Returns the value of the bit with the specified index. The value
* is {@code true} if the bit with the index {@code bitIndex}
* is currently set in this {@code BitSet}; otherwise, the result
* is {@code false}.
*
* @param bitIndex the bit index
* @return the value of the bit with the specified index
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public boolean get(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
checkInvariants();
int wordIndex = wordIndex(bitIndex);
return (wordIndex < wordsInUse)
&& ((words[wordIndex] & (1L << bitIndex)) != 0);
}
首先wordIndex(bitIndex);获取bitIndex在数组中的下标,然后再判断bitIndex位对应位是否为1,是则返回true,表示元素存在,否则返回false,表示元素不存在。
总体来说,BitSet是BitMap的Java实现,其内部使用long[]存储元素,每个数组元素可以表示64个数字,数组元素的每一位对应一个数字,为0表示对应的数字不存在,为1表示对应的数字存在。
可以使用BitSet来进行排序、去重等。