jdk源码解析--BitSet类
Posted 我的IT技术路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--BitSet类相关的知识,希望对你有一定的参考价值。
Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。Bitset的每一个元素都有一个boolean值,每个值相互独立,并且都有一个非负整数指引。Jdk大概是上面那样介绍这个类的,好吧,现在我们主要看下其具体的实现逻辑。
先看下这个类的实现基本框架:
1. public class BitSet implements Cloneable, java.io.Serializable {
2. private final static int ADDRESS_BITS_PER_WORD = 6;//一个long型对应6个字节
3. private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;//初始化长度
4. private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
5. private static final long WORD_MASK = 0xffffffffffffffffL;
6. private long[] words;//内部使用long存入每个位集
7. private transient int wordsInUse = 0;//words数组已经使用的个数
8. private transient boolean sizeIsSticky = false;//是否指定words数组的大小
9. public BitSet() {
10. initWords(BITS_PER_WORD);
11. sizeIsSticky = false;
12. }
13. public BitSet(int nbits) {
14. // 不能小于0
15. if (nbits < 0)
16. throw new NegativeArraySizeException("nbits < 0: " + nbits);
17.
18. initWords(nbits);//初始化长度
19. sizeIsSticky = true;
20. }
21. }
实现的函数逻辑:
Valueof:这个函数有几种实现方法,分别是将Long类,Byte类型,相应的buffer类型转换成BitSet类。
1. public static BitSet valueOf(long[] longs) {
2. int n;
3. for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)//定位到数组中不为0的位置
4. ;
5. return new BitSet(Arrays.copyOf(longs, n));//创建一个新的BitSet
6. }
1. public static BitSet valueOf(ByteBuffer bb) {
2. bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
3. int n;
4. for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)//将0去除掉
5. ;
6. long[] words = new long[(n + 7) / 8];//计算words的长度,并初始化
7. bb.limit(n);
8. int i = 0;
9. while (bb.remaining() >= 8)//大于8,直接取出long类型
10. words[i++] = bb.getLong();
11. for (int remaining = bb.remaining(), j = 0; j < remaining; j++)//剩余不满8处理
12. words[i] |= (bb.get() & 0xffL) << (8 * j);
13. return new BitSet(words);
14. }
Flip:将BitSet当前位置的补码
1. public void flip(int bitIndex) {
2. if (bitIndex < 0)
3. throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
4.
5. int wordIndex = wordIndex(bitIndex);//将bitindex转换到wordindex
6. expandTo(wordIndex);//扩容
7.
8. words[wordIndex] ^= (1L << bitIndex);//求补
9.
10. recalculateWordsInUse();//重新计算
11. checkInvariants();//校验
12. }
13. private static int wordIndex(int bitIndex) {
14. return bitIndex >> ADDRESS_BITS_PER_WORD;
15. }
16. private void expandTo(int wordIndex) {
17. int wordsRequired = wordIndex+1;
18. if (wordsInUse < wordsRequired) {//系统扩容
19. ensureCapacity(wordsRequired);
20. wordsInUse = wordsRequired;
21. }
22. }
23. private void ensureCapacity(int wordsRequired) {
24. if (words.length < wordsRequired) {
25. // Allocate larger of doubled size or required size
26. int request = Math.max(2 * words.length, wordsRequired);//扩容,2倍或者是最大长度
27. words = Arrays.copyOf(words, request);//系统拷贝
28. sizeIsSticky = false;
29. }
30. }
31. private void recalculateWordsInUse() {//重新计算已经使用的长度
32. // Traverse the bitset until a used word is found
33. int i;
34. for (i = wordsInUse-1; i >= 0; i--)//从后往前查找到不为0的位置
35. if (words[i] != 0)
36. break;
37.
38. wordsInUse = i+1; // 已经使用的大小
39. }
40. private void checkInvariants() {//校验
41. assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
42. assert(wordsInUse >= 0 && wordsInUse <= words.length);
43. assert(wordsInUse == words.length || words[wordsInUse] == 0);
44. }
Set:将指定的位置设置为true
1. public void set(int bitIndex) {
2. if (bitIndex < 0)
3. throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
4.
5. int wordIndex = wordIndex(bitIndex);//获取位置
6. expandTo(wordIndex);//扩容
7.
8. words[wordIndex] |= (1L << bitIndex); // 设置为true
9.
10. checkInvariants();//校验
11. }
Clear:将指定位置设置为false
1. public void clear(int fromIndex, int toIndex) {
2. checkRange(fromIndex, toIndex);//检验范围
3.
4. if (fromIndex == toIndex)//如果头尾相等
5. return;
6.
7. int startWordIndex = wordIndex(fromIndex);//找到开始点
8. if (startWordIndex >= wordsInUse)
9. return;
10.
11. int endWordIndex = wordIndex(toIndex - 1);//找到末尾点
12. if (endWordIndex >= wordsInUse) {
13. toIndex = length();
14. endWordIndex = wordsInUse - 1;
15. }
16.
17. long firstWordMask = WORD_MASK << fromIndex;
18. long lastWordMask = WORD_MASK >>> -toIndex;
19. if (startWordIndex == endWordIndex) {
20. //如果只有一个字节
21. words[startWordIndex] &= ~(firstWordMask & lastWordMask);
22. } else {
23. // 多个字节
24. // 处理第一个字节
25. words[startWordIndex] &= ~firstWordMask;
26.
27. // 处理中间字节
28. for (int i = startWordIndex+1; i < endWordIndex; i++)
29. words[i] = 0;
30.
31. // 处理最后一个字节
32. words[endWordIndex] &= ~lastWordMask;
33. }
34.
35. recalculateWordsInUse();//重新计算使用的个数
36. checkInvariants();//校验
37. }
Get:获取指定位置的值
1. public boolean get(int bitIndex) {
2. if (bitIndex < 0)
3. throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
4.
5. checkInvariants();//校验
6.
7. int wordIndex = wordIndex(bitIndex);//获取值
8. return (wordIndex < wordsInUse)//如果是已用范围内
9. && ((words[wordIndex] & (1L << bitIndex)) != 0);//取出值不为0
10. }
nextSetBit:返回从指定位置开始的第一个true的位置
1. public int nextSetBit(int fromIndex) {
2. if (fromIndex < 0)
3. throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
4.
5. checkInvariants();//检验
6.
7. int u = wordIndex(fromIndex);//求出index对应的位子
8. if (u >= wordsInUse)//如果大于已经使用的
9. return -1;
10.
11. long word = words[u] & (WORD_MASK << fromIndex);
12.
13. while (true) {
14. if (word != 0)//找到不为 0的值
15. return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
16. if (++u == wordsInUse)//如果没找到
17. return -1;
18. word = words[u];
19. }
20. }
nextClearBit:从指定位置返回第一个false的值
previousSetBit:从指定位置之前返回第一个true的值
previousClearBit:从指定位置之前返回第一个false的值,这几个函数和上面的实现类似,读者自行解读。
Length:
1. public int length() {
2. if (wordsInUse == 0)
3. return 0;
4.
5. return BITS_PER_WORD * (wordsInUse - 1) +
6. (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));//返回计算的长度
7. }
Intersects:返回两个bitset是否有相同的位置为true
1. public boolean intersects(BitSet set) {
2. for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)//取两者的最小值开始
3. if ((words[i] & set.words[i]) != 0)//如果两个值都是true
4. return true;
5. return false;
6. }
Cardinality:统计bitset中true的数字
1. public int cardinality() {
2. int sum = 0;
3. for (int i = 0; i < wordsInUse; i++)
4. sum += Long.bitCount(words[i]);//累计true的位置
5. return sum;
6. }
And:逻辑与
1. public void and(BitSet set) {
2. if (this == set)
3. return;
4.
5. while (wordsInUse > set.wordsInUse)//先将多余的位置置为false
6. words[--wordsInUse] = 0;
7.
8. // Perform logical AND on words in common
9. for (int i = 0; i < wordsInUse; i++)//进行与操作
10. words[i] &= set.words[i];
11.
12. recalculateWordsInUse();
13. checkInvariants();
14. }
Or,xor,andnot实现类似,注意andnot是与已知的bitset取反后按位与。剩下的hashcode,equals,clone等基本方法,实现相对简单,读者可自行查看源码。
Stream:返回的是对应的整型流
1. public IntStream stream() {//转换为对应的整型流
2. class BitSetIterator implements PrimitiveIterator.OfInt {//迭代器
3. int next = nextSetBit(0);
4.
5. @Override
6. public boolean hasNext() {
7. return next != -1;
8. }
9.
10. @Override
11. public int nextInt() {
12. if (next != -1) {
13. int ret = next;
14. next = nextSetBit(next+1);
15. return ret;
16. } else {
17. throw new NoSuchElementException();
18. }
19. }
20. }
21.
22. return StreamSupport.intStream(
23. () -> Spliterators.spliterator(
24. new BitSetIterator(), cardinality(),
25. Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
26. Spliterator.SIZED | Spliterator.SUBSIZED |
27. Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
28. false);
29. }
以上是关于jdk源码解析--BitSet类的主要内容,如果未能解决你的问题,请参考以下文章