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。
分享到:
相关推荐
解决no such provider: BC 问题所需的JAR 在jdk中的jre\lib\security修改java.security文件, security.provider.6=com.sun.security.sasl.Provider 下面添加...bcprov-jdk16-143.jar提供加密,解密,生成密钥对等方法
bcprov-jdk16-143.jar提供加密,解密,生成密钥对等方法
jdk-8u311-windows-x64.exe jdk-8u311-windows-x64.exe.zip jdk-8u311-windows-x64.exe jdk-8u311-windows-x64.exe.zip jdk-8u311-windows-x64.exe jdk-8u311-windows-x64.exe.zip jdk-8u311-windows-x64.exe jdk-8u...
bcprov-jdk15-133.jar bcprov-jdk15-133.jar
这个压缩包 "jdk8-jdk-8u121-linux-x64.tar.gz" 包含了适用于Linux 64位系统的JDK 8更新121版本。** JDK是Java SE(Standard Edition)的一部分,它提供了Java编程语言和Java平台的开发环境。这个版本号“8u121”指...
解决no such provider: BC 问题所需的JAR 在jdk中的jre\lib\security修改java.security文件, security.provider.6=com.sun.security.sasl.Provider 下面添加 ...在\jre\lib\ext中添加bcprov-jdk15-135.jar的jar包
java中对pdf文件操作,若要加密,需要这个包。 注意bcprov有许多版本,如bcprov-jdk16-145.jar, 请确认你的iText包的版本,本包适用于iText-2.0.1.jar版
JDK1.7版本的源码提供了对Java语言核心库的深入洞察,而sun包下的源码更是其中的重要组成部分,因为它们包含了Java的核心实现和一些私有API。然而,标准的JDK1.7发行版并未包含完整的sun包源码,这给开发者带来了...
`json-lib-2.4-jdk15-sources.jar`是这个库的源码版本,适用于JDK 1.5环境。源码文件对于开发者来说非常宝贵,因为它允许我们深入理解库的内部工作原理,调试问题,甚至进行自定义扩展。 `json-lib`库支持以下功能...
jdk 1.8 -32位,文件过大,百度云盘连接,下载可用,要用的可以下载哦
标题中的"bcprov-jdk15on-1.64运行包及源码.zip"指的是Bouncy Castle Provider的Java版本1.64的运行时库和源代码压缩包。Bouncy Castle是一个开源的Java安全库,它提供了加密、数字签名、PKI(公钥基础设施)以及SSL...
Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包.CXF中的ws安全可能需要使用。 org.bouncycastle
slf4j-jdk14-1.7.7.jar
协同过滤推荐算法(java原生JDK实现-附源码地址).pdf协同过滤推荐算法(java原生JDK实现-附源码地址).pdf协同过滤推荐算法(java原生JDK实现-附源码地址).pdf协同过滤推荐算法(java原生JDK实现-附源码地址).pdf协同过滤...
bcprov-jdk16-141.jar
2. 阅读JDK库源码:了解常用API的实现细节,如Collections、Concurrent包等。 3. 探索HotSpot:深入理解虚拟机如何执行字节码,分析编译器的工作流程。 4. 学习内存管理:研究不同的垃圾收集器,了解其工作原理和...
jdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586.exejdk-6-windows-i586....
随着源码一起提供的文档可能包括API参考、用户指南和开发者教程,帮助开发者了解如何使用Bouncy Castle提供的各种功能,例如设置安全参数、创建和验证数字签名、实现加密通信等。 5. **版本更新**: 提到的2020年...
Centos7离线安装文件 jdk-8u231-linux-x64.tar.gz压缩包 免费下载,现在博客都是付费文件,搞得头大,现在免费分享
与bcmail-jdk16-146.jar,lcrypto-jdk15.jar配合使用,作用与java ZIP的压缩、解压缩(同时加解密)