java中BitSet详解

该类在java的java.util包中。

BitSet类的原理主要是利用long型有64个bit,每个bit存储一个数值,这样一个long型数字就能存储64个数字,进而节省了空间。接下来我们开始讲解该类的代码。

我们先看一下该类的成员变量:

/*
     * BitSets are packed into arrays of "words."  Currently a word is
     * a long, which consists of 64 bits, requiring 6 address bits.
     * The choice of word size is determined purely by performance concerns.
     */
    private final static int ADDRESS_BITS_PER_WORD = 6;
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;

    /* Used to shift left or right for a partial word mask */
    private static final long WORD_MASK = 0xffffffffffffffffL;

    /**
     * @serialField bits long[]
     *
     * The bits in this BitSet.  The ith bit is stored in bits[i/64] at
     * bit position i % 64 (where bit position 0 refers to the least
     * significant bit and 63 refers to the most significant bit).
     */
    private static final ObjectStreamField[] serialPersistentFields = {
        new ObjectStreamField("bits", long[].class),
    };

    /**
     * The internal field corresponding to the serialField "bits".
     *  //存储数据,一个元素可以存储64个数据
     */
    private long[] words;

    /**
     * The number of words in the logical size of this BitSet.
     * 当前已经在使用了的数组元素个数
     */
    private transient int wordsInUse = 0;

    /**
     * Whether the size of "words" is user-specified.  If so, we assume
     * the user knows what he's doing and try harder to preserve it.
     * 是否指定words数组的大小,如果是那么就为true,否则为false。
     */
    private transient boolean sizeIsSticky = false;

    /* use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = 7997698588986878753L;

接下来我们开始分析函数:

1、wordIndex函数,代码如下:

/**
     * Given a bit index, return word index containing it.
     */
    private static int wordIndex(int bitIndex) {
        return bitIndex >> ADDRESS_BITS_PER_WORD;
    }

这个函数用来获取某个数在words数组中的索引,这里通过bitIndex右移ADDRESS_BITS_PER_WORD位,即右移6位,为什么是6位呢?

我们知道在正常情况下,右移n位得到的值为原值除以2的n次方,而2的6次方是64,也就是bitIndex/64,我们之前说过,words数组中每个元素能够代表64个数字,所以存储的值除以64来得到数组索引值,例如0到63的索引值为0,那么这64个数字划归到第一个数组元素中,64到127划归到第二个数组元素中,以此类推。

2、checkInvariants()函数,代码如下:

/**
     * 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、recalculateWordsInUse()函数,代码如下:

/**
     * Sets the field wordsInUse to the logical size in words of the bit set.
     * WARNING:This method assumes that the number of words actually in use is
     * less than or equal to the current value of wordsInUse!
     */
    private void recalculateWordsInUse() {
        // Traverse the bitset until a used word is found
        int i;
        for (i = wordsInUse-1; i >= 0; i--)
            if (words[i] != 0)
                break;

        wordsInUse = i+1; // The new logical size
    }

这个函数用来计算当前已经使用了的最大数组元素个数。

4、initWords函数,代码如下:

private void initWords(int nbits) {
   words = new long[wordIndex(nbits-1) + 1];
}

这个函数用来创建数组words,该数组元素大小通过wordIndex(nbits-1)+1来获取,而wordIndex上面我们讲了,用来得到某个值所在words数组的索引,然后创建words数组的时候一定要保证数组个数大于等于该值所在的索引值。

5、构造函数

/**
     * Creates a new bit set. All bits are initially {@code false}.
     */
    public BitSet() {
        //创建一个words数组,大小为1
        initWords(BITS_PER_WORD);
        //该数组大小不限定
        sizeIsSticky = false;
    }

    /**
     * Creates a bit set whose initial size is large enough to explicitly
     * represent bits with indices in the range {@code 0} through
     * {@code nbits-1}. All bits are initially {@code false}.
     *
     * @param  nbits the initial size of the bit set
     * @throws NegativeArraySizeException if the specified initial size
     *         is negative
     */
    public BitSet(int nbits) {
        // nbits can't be negative; size 0 is OK
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);
         
        initWords(nbits);
        //该数组大小限定
        sizeIsSticky = true;
    }

    /**
     * Creates a bit set using words as the internal representation.
     * The last word (if there is one) must be non-zero.
     */
    private BitSet(long[] words) {
        //将该数组赋值给BitSet对象中的words数组
        this.words = words;
        //将当前数组正在使用的最大数组索引设置为数组元素大小
        this.wordsInUse = words.length;
        //验证当前对象的合法性
        checkInvariants();
    }

6、valueof函数,代码如下:

 /**
     * Returns a new bit set containing all the bits in the given long array.
     *
     * <p>More precisely,
     * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
     * <br>for all {@code n < 64 * longs.length}.
     *
     * <p>This method is equivalent to
     * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
     *
     * @param longs a long array containing a little-endian representation
     *        of a sequence of bits to be used as the initial bits of the
     *        new bit set
     * @return a {@code BitSet} containing all the bits in the long array
     * @since 1.7
     */
    public static BitSet valueOf(long[] longs) {
        int n;
        //倒序从longs数组中获取第一个不为0的元素所在的索引值
        for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
            ;
        //从longs数组中拷贝索引从0到n的元素,放到新创建的数组中,然后将该新数组构造BitSet类对象
        return new BitSet(Arrays.copyOf(longs, n));
    }

    /**
     * Returns a new bit set containing all the bits in the given long
     * buffer between its position and limit.
     *
     * <p>More precisely,
     * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
     * <br>for all {@code n < 64 * lb.remaining()}.
     *
     * <p>The long buffer is not modified by this method, and no
     * reference to the buffer is retained by the bit set.
     *
     * @param lb a long buffer containing a little-endian representation
     *        of a sequence of bits between its position and limit, to be
     *        used as the initial bits of the new bit set
     * @return a {@code BitSet} containing all the bits in the buffer in the
     *         specified range
     * @since 1.7
     */
     //其实就是将LongBuffer类对象中从position到limit中的数(倒序遍历,找到第一个不为0的数,将该数的位置当做limit)拷贝到long数组中,同时创建BitSet类对象
    public static BitSet valueOf(LongBuffer lb) {
        //创建一个新的LongBuffer类对象,该对象的容量是原始缓冲区的剩余元素数量(limit - 
        position),position为0,新对象中的值从原缓冲区中拷贝而来(从position到limit之间的值)
        lb = lb.slice();
        int n;
        //倒序遍历新的LongBuffer类对象,直到遇到第一个不为0的值,remaining函数用来获取LongBuffer中从position到limit之间的值个数
        for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
            ;
        //创建数组
        long[] words = new long[n];
        //获取lb中从0开始到n的数据,同时拷贝到words数组中
        lb.get(words);
        //创建BitSet类对象
        return new BitSet(words);
    }

    /**
     * Returns a new bit set containing all the bits in the given byte array.
     *
     * <p>More precisely,
     * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
     * <br>for all {@code n <  8 * bytes.length}.
     *
     * <p>This method is equivalent to
     * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
     *
     * @param bytes a byte array containing a little-endian
     *        representation of a sequence of bits to be used as the
     *        initial bits of the new bit set
     * @return a {@code BitSet} containing all the bits in the byte array
     * @since 1.7
     */
    public static BitSet valueOf(byte[] bytes) {
        //将bytes数组中的数拷贝到BitSet类对象中
        return BitSet.valueOf(ByteBuffer.wrap(bytes));
    }

    /**
     * Returns a new bit set containing all the bits in the given byte
     * buffer between its position and limit.
     *
     * <p>More precisely,
     * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
     * <br>for all {@code n < 8 * bb.remaining()}.
     *
     * <p>The byte buffer is not modified by this method, and no
     * reference to the buffer is retained by the bit set.
     *
     * @param bb a byte buffer containing a little-endian representation
     *        of a sequence of bits between its position and limit, to be
     *        used as the initial bits of the new bit set
     * @return a {@code BitSet} containing all the bits in the buffer in the
     *         specified range
     * @since 1.7
     */
    public static BitSet valueOf(ByteBuffer bb) {
        bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
        int n;
        for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
            ;
        long[] words = new long[(n + 7) / 8];
        bb.limit(n);
        int i = 0;
        while (bb.remaining() >= 8)
            words[i++] = bb.getLong();
        for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
            words[i] |= (bb.get() & 0xffL) << (8 * j);
        return new BitSet(words);
    }

7、toByteArray()函数,代码如下:

/**
     * Returns a new byte array containing all the bits in this bit set.
     *
     * <p>More precisely, if
     * <br>{@code byte[] bytes = s.toByteArray();}
     * <br>then {@code bytes.length == (s.length()+7)/8} and
     * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
     * <br>for all {@code n < 8 * bytes.length}.
     *
     * @return a byte array containing a little-endian representation
     *         of all the bits in this bit set
     * @since 1.7
    */
    public byte[] toByteArray() {
        //获取当前有效的数组大小
        int n = wordsInUse;
        if (n == 0)
            return new byte[0];
        //一个数组元素有8个字节,所以总字节数为8*(n-1)+最后一个元素的有效字节数
        int len = 8 * (n-1);
        /*
        (1)、>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后 
             高位,同样补0。
        
        (2)、这是一个循环,对最后一个元素的每一个8位进行判断(从低位到高位),第一次循环,如果该元素 
             不为0,那么len++,然后右移8位,此时原来的元素只保留了3个字节(另外一个字节被移除掉了, 
             在最左边的1个字节用00000000表示,如果不为0,那么len++,继续右移8位,依次下去,直到遇到 
             值为0为止)
        
        (3)、总结:
             关于移位,总的原则就是:
             如果左边第一个字节有值那么len+4;
             如果左边第一个自己没有值,第二个字节有值那么len+3;
             ..... 
        */
        for (long x = words[n - 1]; x != 0; x >>>= 8)
            len++;
        //获取到len的总值后,创建byte数组对象
        byte[] bytes = new byte[len];
        //通过bytes创建ByteBuffer类对象(其实就是HeapByteBuffer类对象),然后设置排序方式(低位排序和高位排序)
        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
        //循环,将words中的元素存储到ByteBuffer中(存储的时候采用上面设置的排序方式)
        for (int i = 0; i < n - 1; i++)
            bb.putLong(words[i]);
        //对words中最后一个元素进行处理,一个字节一个字节的存储
        for (long x = words[n - 1]; x != 0; x >>>= 8)
            bb.put((byte) (x & 0xff));
        return bytes;
    }

8、toLongArray()函数,代码如下:

/**
     * Returns a new long array containing all the bits in this bit set.
     *
     * <p>More precisely, if
     * <br>{@code long[] longs = s.toLongArray();}
     * <br>then {@code longs.length == (s.length()+63)/64} and
     * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
     * <br>for all {@code n < 64 * longs.length}.
     *
     * @return a long array containing a little-endian representation
     *         of all the bits in this bit set
     * @since 1.7
    */
    public long[] toLongArray() {
        return Arrays.copyOf(words, wordsInUse);
    }

这个函数用来返回一个long数组,该数组的数组是新创建的,将words数组从0开始,拷贝wordsInUse个到新创建的数组中

9、ensureCapacity()函数,代码如下:

/**
     * Ensures that the BitSet can hold enough words.
     * @param wordsRequired the minimum acceptable number of words.
     */
    private void ensureCapacity(int wordsRequired) {
        //如果words的大小小于所需要的
        if (words.length < wordsRequired) {
            // Allocate larger of doubled size or required size
            //扩容最终的大小,最小为原来的两倍
            int request = Math.max(2 * words.length, wordsRequired);
            //创建新的数组,容量为request,然后将原来的数组拷贝到新的数组中
            words = Arrays.copyOf(words, request);
            //数组大小不固定的标志
            sizeIsSticky = false;
        }
    }

这个函数用来动态扩容

10、expandTo()函数,代码如下:

/**
     * 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;
        }
    }

根据数组索引来判断是否要扩容

11、checkRange()函数,代码如下:

/**
     * Checks that fromIndex ... toIndex is a valid range of bit indices.
     */
    private static void checkRange(int fromIndex, int toIndex) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
        if (toIndex < 0)
            throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
        if (fromIndex > toIndex)
            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
                                                " > toIndex: " + toIndex);
    }

参数验证,确保取值范围符合要求

12、flip()函数,代码如下:

/**
     * Sets the bit at the specified index to the complement of its
     * current value.
     *
     * @param  bitIndex the index of the bit to flip
     * @throws IndexOutOfBoundsException if the specified index is negative
     * @since  1.4
     */
    public void flip(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        int wordIndex = wordIndex(bitIndex);
        expandTo(wordIndex);
        
        /*^运算符规则为"相同则为0,不相同则为1",
       1L << bitIndex(注意这里其实在移位运算的时候是bitIndex对64取模)是将bitIndex位的值设置为1, 
       例如:
       bitIndex为1,那么1L << bitIndex就为:
       00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
       左移1位后
       00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000010
       最后将移位后的二进制值去跟words[wordIndex]去异或运算
       这个是什么意思呢,如果在words[wordIndex]上位数为这个值(bitIndex对64取模后的值)的地方有值,也就是1,那么异或后就为0,其他位置有值的变成1,没有值的为0,也就是说其他位的值不变,最终就是将bitIndex对64取模后的值所在的位置的值取反。
        */
        words[wordIndex] ^= (1L << bitIndex);
       
        recalculateWordsInUse();
        checkInvariants();
    }

/**
     * Sets each bit from the specified {@code fromIndex} (inclusive) to the
     * specified {@code toIndex} (exclusive) to the complement of its current
     * value.
     *
     * @param  fromIndex index of the first bit to flip
     * @param  toIndex index after the last bit to flip
     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
     *         or {@code toIndex} is negative, or {@code fromIndex} is
     *         larger than {@code toIndex}
     * @since  1.4
     */
    public void flip(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

        int startWordIndex = wordIndex(fromIndex);
        int endWordIndex   = wordIndex(toIndex - 1);
        expandTo(endWordIndex);
        
        //左移fromIndex位(将WORD_MASK上第fromIndex位的bit设置为0,例如fromIndex为1,表示将右边第一位设置为0)
        long firstWordMask = WORD_MASK << fromIndex;
        //无符号右移-toIndex位,也就是64-toIndex%64位(将WORD_MASK上无符号右移64-toIndex%64位)
        long lastWordMask  = WORD_MASK >>> -toIndex;
        //如果都在一个words数组元素中
        if (startWordIndex == endWordIndex) {
            // Case 1: One word
            //进行异或操作(相同为0,不同为1)
            words[startWordIndex] ^= (firstWordMask & lastWordMask);
        } else {
            // Case 2: Multiple words
            // Handle first word
            //单独对起始的words元素进行取反
            words[startWordIndex] ^= firstWordMask;

            // Handle intermediate words, if any
            //将包含在startWordIndex(不包括)到endWordIndex(不包括)之间的words数组元素全部取反
            for (int i = startWordIndex+1; i < endWordIndex; i++)
                words[i] ^= WORD_MASK;

            // Handle last word
            //单独对最后的words元素进行取反
            words[endWordIndex] ^= lastWordMask;
        }

        recalculateWordsInUse();
        checkInvariants();
    }

综上所述,flip函数用来将指定的位数取反操作,也就是原来位为0,取反后变成1,原来为1,取反后变成0。

13、set函数,代码如下:

/**
     * 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);
        //将指定的bitIndex位设置成1
        words[wordIndex] |= (1L << bitIndex); // Restores invariants

        checkInvariants();
    }

    /**
     * Sets the bit at the specified index to the specified value.
     *
     * @param  bitIndex a bit index
     * @param  value a boolean value to set
     * @throws IndexOutOfBoundsException if the specified index is negative
     * @since  1.4
     */
    public void set(int bitIndex, boolean value) {
        if (value)
            set(bitIndex);
        else
            clear(bitIndex);
    }

    /**
     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
     * specified {@code toIndex} (exclusive) to {@code true}.
     *
     * @param  fromIndex index of the first bit to be set
     * @param  toIndex index after the last bit to be set
     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
     *         or {@code toIndex} is negative, or {@code fromIndex} is
     *         larger than {@code toIndex}
     * @since  1.4
     */
    //这个函数与flip函数逻辑差不多,只不过这里采用的是'或'操作,相信了解了flip函数逻辑的就能看明白了,这里不做赘述
    public void set(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

        // Increase capacity if necessary
        int startWordIndex = wordIndex(fromIndex);
        int endWordIndex   = wordIndex(toIndex - 1);
        expandTo(endWordIndex);

        long firstWordMask = WORD_MASK << fromIndex;
        long lastWordMask  = WORD_MASK >>> -toIndex;
        if (startWordIndex == endWordIndex) {
            // Case 1: One word
            words[startWordIndex] |= (firstWordMask & lastWordMask);
        } else {
            // Case 2: Multiple words
            // Handle first word
            words[startWordIndex] |= firstWordMask;

            // Handle intermediate words, if any
            for (int i = startWordIndex+1; i < endWordIndex; i++)
                words[i] = WORD_MASK;

            // Handle last word (restores invariants)
            words[endWordIndex] |= lastWordMask;
        }

        checkInvariants();
    }

    /**
     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
     * specified {@code toIndex} (exclusive) to the specified value.
     *
     * @param  fromIndex index of the first bit to be set
     * @param  toIndex index after the last bit to be set
     * @param  value value to set the selected bits to
     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
     *         or {@code toIndex} is negative, or {@code fromIndex} is
     *         larger than {@code toIndex}
     * @since  1.4
     */
    public void set(int fromIndex, int toIndex, boolean value) {
        if (value)
            set(fromIndex, toIndex);
        else
            clear(fromIndex, toIndex);
    }

set函数用来将指定的位设置为1

14、clear函数,代码如下:

/**
     * Sets the bit specified by the index to {@code false}.
     *
     * @param  bitIndex the index of the bit to be cleared
     * @throws IndexOutOfBoundsException if the specified index is negative
     * @since  JDK1.0
     */
    public void clear(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        int wordIndex = wordIndex(bitIndex);
        if (wordIndex >= wordsInUse)
            return;

        words[wordIndex] &= ~(1L << bitIndex);

        recalculateWordsInUse();
        checkInvariants();
    }

    /**
     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
     * specified {@code toIndex} (exclusive) to {@code false}.
     *
     * @param  fromIndex index of the first bit to be cleared
     * @param  toIndex index after the last bit to be cleared
     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
     *         or {@code toIndex} is negative, or {@code fromIndex} is
     *         larger than {@code toIndex}
     * @since  1.4
     */
    public void clear(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

        int startWordIndex = wordIndex(fromIndex);
        if (startWordIndex >= wordsInUse)
            return;

        int endWordIndex = wordIndex(toIndex - 1);
        if (endWordIndex >= wordsInUse) {
            toIndex = length();
            endWordIndex = wordsInUse - 1;
        }

        long firstWordMask = WORD_MASK << fromIndex;
        long lastWordMask  = WORD_MASK >>> -toIndex;
        if (startWordIndex == endWordIndex) {
            // Case 1: One word
            words[startWordIndex] &= ~(firstWordMask & lastWordMask);
        } else {
            // Case 2: Multiple words
            // Handle first word
            words[startWordIndex] &= ~firstWordMask;

            // Handle intermediate words, if any
            for (int i = startWordIndex+1; i < endWordIndex; i++)
                words[i] = 0;

            // Handle last word
            words[endWordIndex] &= ~lastWordMask;
        }

        recalculateWordsInUse();
        checkInvariants();
    }

    /**
     * Sets all of the bits in this BitSet to {@code false}.
     *
     * @since 1.4
     */
    public void clear() {
        while (wordsInUse > 0)
            words[--wordsInUse] = 0;
    }

这个函数用来将指定的位设置成0

15、get函数,代码如下:

/**
     * 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);
        /*
        1、首先保证没有越界,否则返回false
        2、然后通过1L << bitIndex,将bitIndex位设置为1
        3、将2中左移的值和words中索引为wordIndex的值进行&操作
        4、如果bitIndex位的值为1,那么&操作后该位的值就为1,此时
           对应的words元素值不为0,所以返回true。
           如果bitIndex位的值为0,那么&操作后该位的值就为0,此时
           对应的words元素值为0,所以返回false。
        */
        return (wordIndex < wordsInUse)
            && ((words[wordIndex] & (1L << bitIndex)) != 0);
    }

    /**
     * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
     * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
     *
     * @param  fromIndex index of the first bit to include
     * @param  toIndex index after the last bit to include
     * @return a new {@code BitSet} from a range of this {@code BitSet}
     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
     *         or {@code toIndex} is negative, or {@code fromIndex} is
     *         larger than {@code toIndex}
     * @since  1.4
     */
    public BitSet get(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        checkInvariants();

        int len = length();

        // If no set bits in range return empty bitset
        if (len <= fromIndex || fromIndex == toIndex)
            return new BitSet(0);

        // An optimization
        if (toIndex > len)
            toIndex = len;

        BitSet result = new BitSet(toIndex - fromIndex);
        int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
        int sourceIndex = wordIndex(fromIndex);
        boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);

        // Process all words but the last word
        for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
            result.words[i] = wordAligned ? words[sourceIndex] :
                (words[sourceIndex] >>> fromIndex) |
                (words[sourceIndex+1] << -fromIndex);

        // Process the last word
        long lastWordMask = WORD_MASK >>> -toIndex;
        result.words[targetWords - 1] =
            ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
            ? /* straddles source words */
            ((words[sourceIndex] >>> fromIndex) |
             (words[sourceIndex+1] & lastWordMask) << -fromIndex)
            :
            ((words[sourceIndex] & lastWordMask) >>> fromIndex);

        // Set wordsInUse correctly
        result.wordsInUse = targetWords;
        result.recalculateWordsInUse();
        result.checkInvariants();

        return result;
    }

get函数用来获取某一位是否有效,或者获取某个BitSet类对象的指定范围的数值到一个新的BitSet类对象中

16、nextSetBit()函数,代码如下:

/**
     * Returns the index of the first bit that is set to {@code true}
     * that occurs on or after the specified starting index. If no such
     * bit exists then {@code -1} is returned.
     *
     * <p>To iterate over the {@code true} bits in a {@code BitSet},
     * use the following loop:
     *
     *  <pre> {@code
     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
     *     // operate on index i here
     *     if (i == Integer.MAX_VALUE) {
     *         break; // or (i+1) would overflow
     *     }
     * }}</pre>
     *
     * @param  fromIndex the index to start checking from (inclusive)
     * @return the index of the next set bit, or {@code -1} if there
     *         is no such bit
     * @throws IndexOutOfBoundsException if the specified index is negative
     * @since  1.4
     */
    public int nextSetBit(int fromIndex) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);

        checkInvariants();

        int u = wordIndex(fromIndex);
        if (u >= wordsInUse)
            return -1;

        long word = words[u] & (WORD_MASK << fromIndex);

        while (true) {
            if (word != 0)
                //numberOfTrailingZeros函数用来返回最低位的1之后0的个数。例如:1101000即104返 
                //回3
                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
            if (++u == wordsInUse)
                return -1;
            word = words[u];
        }
    }

获取从fromIndex开始第一个设置为1的bit索引值

17、nextClearBit函数,代码如下:

/**
     * Returns the index of the first bit that is set to {@code false}
     * that occurs on or after the specified starting index.
     *
     * @param  fromIndex the index to start checking from (inclusive)
     * @return the index of the next clear bit
     * @throws IndexOutOfBoundsException if the specified index is negative
     * @since  1.4
     */
    public int nextClearBit(int fromIndex) {
        // Neither spec nor implementation handle bitsets of maximal length.
        // See 4816253.
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);

        checkInvariants();

        int u = wordIndex(fromIndex);
        if (u >= wordsInUse)
            return fromIndex;

        long word = ~words[u] & (WORD_MASK << fromIndex);

        while (true) {
            if (word != 0)
                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
            if (++u == wordsInUse)
                return wordsInUse * BITS_PER_WORD;
            word = ~words[u];
        }
    }

获取从fromIndex开始第一个设置为0的bit索引值

18、previousSetBit函数,代码如下:

/**
     * Returns the index of the nearest bit that is set to {@code true}
     * that occurs on or before the specified starting index.
     * If no such bit exists, or if {@code -1} is given as the
     * starting index, then {@code -1} is returned.
     *
     * <p>To iterate over the {@code true} bits in a {@code BitSet},
     * use the following loop:
     *
     *  <pre> {@code
     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
     *     // operate on index i here
     * }}</pre>
     *
     * @param  fromIndex the index to start checking from (inclusive)
     * @return the index of the previous set bit, or {@code -1} if there
     *         is no such bit
     * @throws IndexOutOfBoundsException if the specified index is less
     *         than {@code -1}
     * @since  1.7
     */
    //统计fromIndex前面第一个为1的值
    public int previousSetBit(int fromIndex) {
        if (fromIndex < 0) {
            if (fromIndex == -1)
                return -1;
            throw new IndexOutOfBoundsException(
                "fromIndex < -1: " + fromIndex);
        }

        checkInvariants();

        int u = wordIndex(fromIndex);
        /*这里说明u越界了,所以该函数就变成了统计当前words数组最后一个元素从高位到低为直到遇到第一个为1的位所在的值。
          举一个例子:
          数组总共有10个,如果最后一个数组为:
          00000000 00000000 00000000 00000000 00000000 00000000 00000000 10000000
          那么此时就是统计上面二进制值从高到低为1的bit所在的值,也就是:
          9 * 64 + (64 - 7 * 8 - 1)
          上面(64 - 7 * 8 - 1),之所以-1,是因为它是从0开始的,也就是说最低位为0
        */
        if (u >= wordsInUse)
            return length() - 1;

        /*这里WORD_MASK >>> -(fromIndex+1)主要是将fromIndex位设置为1,然后去跟当前的word值去&,举一个例子:
         words数组有两个元素,fromIndex为65,该值在数组的第二个元素中,words[1]二进制为:
         00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000011
         此时倒数第二个表示65,然后WORD_MASK >>> -(65+1)即相当于WORD_MASK >>> -66也就是
         WORD_MASK >>> 64 - (|-66|%64)最终为WORD_MASK >>> 62。得到的二进制值为:
         00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000011
         此时去和words[1]进行&操作,值为:
         00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000011
         然后进入while循环,返回(1+1)*64 - 1 - 62 = 128 - 63 = 65,所以最终值为65,也就是说65这个值在它之前或者就在它这个位置第一个bit为1的值为65。
如果words[1]的二进制为:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
那么此时就是(1+1)*64 - 1 - 63 = 64,也就是最低位的那个bit所对应的值。

综上来看,它的思想就是:
将该fromIndex所在的bit以及它的低位设置成1,然后去和相应的words数组元素进行&操作(此时fromIndex所在的bit以及它的低位之外的其他bit都变成了0),如果不为0,说明该words元素上有符合要求的bit位,然后查找的规则就是从高位开始查找,直到遇到第一个bit为1的,就是我们要找的
        */
        long word = words[u] & (WORD_MASK >>> -(fromIndex+1));

        while (true) {
            if (word != 0)
                return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
            if (u-- == 0)
                return -1;
            word = words[u];
        }
    }

19、previousClearBit(int fromIndex)函数,代码如下:

/**
     * Returns the index of the nearest bit that is set to {@code false}
     * that occurs on or before the specified starting index.
     * If no such bit exists, or if {@code -1} is given as the
     * starting index, then {@code -1} is returned.
     *
     * @param  fromIndex the index to start checking from (inclusive)
     * @return the index of the previous clear bit, or {@code -1} if there
     *         is no such bit
     * @throws IndexOutOfBoundsException if the specified index is less
     *         than {@code -1}
     * @since  1.7
     */
    public int previousClearBit(int fromIndex) {
        if (fromIndex < 0) {
            if (fromIndex == -1)
                return -1;
            throw new IndexOutOfBoundsException(
                "fromIndex < -1: " + fromIndex);
        }

        checkInvariants();

        int u = wordIndex(fromIndex);
        if (u >= wordsInUse)
            return fromIndex;

        long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));

        while (true) {
            if (word != 0)
                return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
            if (u-- == 0)
                return -1;
            word = ~words[u];
        }
    }

这个函数用来获取fromIndex位置或者之前位置中从高到低,第一个为0的bit对应的值,原理与previousSetBit类似,这里不再赘述

20、length()函数,代码如下:

/**
     * Returns the "logical size" of this {@code BitSet}: the index of
     * the highest set bit in the {@code BitSet} plus one. Returns zero
     * if the {@code BitSet} contains no set bits.
     *
     * @return the logical size of this {@code BitSet}
     * @since  1.2
     */
    public int length() {
        if (wordsInUse == 0)
            return 0;

        return BITS_PER_WORD * (wordsInUse - 1) +
            (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
    }

这个函数比较简单,不做赘述

21、两个函数,代码如下:

/**
     * Returns true if this {@code BitSet} contains no bits that are set
     * to {@code true}.
     *
     * @return boolean indicating whether this {@code BitSet} is empty
     * @since  1.4
     */
    public boolean isEmpty() {
        return wordsInUse == 0;
    }

    /**
     * Returns true if the specified {@code BitSet} has any bits set to
     * {@code true} that are also set to {@code true} in this {@code BitSet}.
     *
     * @param  set {@code BitSet} to intersect with
     * @return boolean indicating whether this {@code BitSet} intersects
     *         the specified {@code BitSet}
     * @since  1.4
     */
    public boolean intersects(BitSet set) {
        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
            if ((words[i] & set.words[i]) != 0)
                return true;
        return false;
    }

这两个函数比较简单

22、cardinality函数,代码如下:

/**
     * Returns the number of bits set to {@code true} in this {@code BitSet}.
     *
     * @return the number of bits set to {@code true} in this {@code BitSet}
     * @since  1.4
     */
    public int cardinality() {
        int sum = 0;
        for (int i = 0; i < wordsInUse; i++)
            sum += Long.bitCount(words[i]);
        return sum;
    }

用来获取words数组中每个元素bit为1的总bit数,关于bitCount函数,可以参考另外一个博客的文章,点击查看另外一篇

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值