`
robertliudeqiang
  • 浏览: 123547 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JDK源码 - BitSet的实现

    博客分类:
  • java
阅读更多
java.util.BitSet是个很有趣的类,了解其内部实现对正确的使用非常重要。

对象构造:

private final static int ADDRESS_BITS_PER_WORD = 6;
private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
private long[] words;

private static int wordIndex(int bitIndex) {
	return bitIndex >> ADDRESS_BITS_PER_WORD;
}

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

public BitSet() {
	initWords(BITS_PER_WORD);
	...
}

public BitSet(int nbits) {
	...
	initWords(nbits);
	...
}


从贴出来的代码可以看出,long[] words这个数组是BitSet内部的关键实现,如果用户在构造函数中输入一个nbits变量,initWords方法会把这个数减1再右移6位加1,按照这个长度产生words数组的长度。
如果是输入的28,那么words的长度是1,
如果是输入的2^6       = 64,那么words的长度是1,
如果是输入的2^6+1     = 65,那么words的长度是2,
如果是输入的(2^6)*2   = 128,那么words的长度是2,
如果是输入的(2^6)*2+1 = 129,那么words的长度是3,
如果是输入的(2^6)*3   = 192,那么words的长度是3,
如果是输入的(2^6)*3+1 = 193,那么words的长度是4,
...

到这里已经很清楚了,BitSet用long类型表示“位图”,因为一个long是64bit,所以每个long表示64个数据,也就是说:数组中words中的第一个long表示0~63,第二个long表示64~127,第三个long表示128~191 ...

再看看get函数,检测某个数是否被置位:
public boolean get(int bitIndex) {
	if (bitIndex < 0)
		throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
...
	int wordIndex = wordIndex(bitIndex);
	return (wordIndex < wordsInUse)
		&& ((words[wordIndex] & (1L << bitIndex)) != 0);
}

说明:
- wordsInUse变量主要用来控制long的容量,当set的数值过大时,BitSet类可以扩充words数组的长度,这一点和很多集合类(例如ArrayList,HashMap)是相似的
- 下面的语句值得注意:
1L << bitIndex
一般看到这条语句,会认为bitIndex如果超过64位,高位会溢出并得到返回0,事实上这个1会重新循环到低位,也就是说:
1L << 64 返回为1。
术语上这叫循环左移,经过检测java同样支持循环右移,运行下面的测试:
	for (int i = 0;i < 70 ;i++)
		System.out.println(i + " =" + (1 >> i));

在i为0,32,64时,(1 >> i)重新为1,搞位运算编程的需要注意这个陷阱。

注: 经过仔细考虑和试验,这里不是循环左移和循环右移,是一种比较“奇怪”的实现,回头写写这个问题。

BitSet类的一个缺陷:
size方法属于类的内部实现细节,导出成公有方法会让不了解实现细节的开发人员很迷惑。

public int size() {
	return words.length * BITS_PER_WORD;
}


例如: 开发人员可能通过bitset.set(100)设置位,然后调用bitset.size(),如果不了解细节,很难理解为什么结果为128。

另外,如果实现位域(bit fields),应该考虑使用EnumSet,这一点可以参考Effective Java。
1
0
分享到:
评论

相关推荐

    javabitset源码-source-code-jdk-8u211:源代码-jdk-8u211

    bitset源码 JAVA 源码研究 使用版本 [jdk-8u211] [环境 IDEA] 构建步骤 1、创建项目结构 rt/ // rt.jar 反编译源码 rtsrc/ // JDK 源码 src/ // 项目源码 2、导入源码 import jdk source of src.zip import jdk ...

    BitSet 源码分析.txt

    基于JDK1.8的BitSet 源码分析, 描述了实现的原理 个方法的含义 虽然没有写出实际的测试代码 但是只要是细度了我的这个分析 在使用的时候就不是问题了

    javabitset源码-read-jdk8:阅读JDK8源码,写一些解释

    bitset源码 Learn JDK 8 学习 JDK 8 源码设计。 阅读前的准备 下载 jdk1.8.0_211,将其中的 src.zip 文件解压。解压后目录如下(部分已省略): └─src └─java ├─io ├─lang ├─math ├─net ├─nio ├─...

    javabitset源码-Java8-learning:学习Java8新特性

    bitset 源码 对于Java开发者来说,Java8的版本显然是一个具有里程碑意义的版本,蕴含了许多令人激动的新特性,如果能利用好这些新特性,能够大大提升我们的开发效率。Java8的函数式编程能够大大减少代码量和便于维护...

    JDK11_DSA_SrcComment:在JDK 11中阅读数据结构和算法(DSA)的注意事项

    这个项目可能是为了帮助开发者更好地理解JDK 11中实现的各种内部机制,从而提升编程技能和效率。 JDK(Java Development Kit)是Java编程语言的标准版开发工具集,包含了编译器、运行时环境和各种实用工具。版本11...

Global site tag (gtag.js) - Google Analytics