【JAVA基础】BitSet
来源:互联网 发布:程序员之死女主角 编辑:程序博客网 时间:2024/06/05 02:58
- 修改记录
- 名词解释
- 存储实现
- 1 setint bitIndex
- expandTo
- ensureCapacity
1 修改记录
2 名词解释
为了方便讲解和理解,本文自定义了部分名词,再次说明:
【目标数字】
bitIndex
,指需要被存储的数字。通常是BitSet.set()
方法的参数;【仓库数字】
word
,指用来存储目标数字的long类型数字。默认该数字为0L;【仓库】
words
,指仓库数字的集合。默认长度为1;【需求数量】
wordsRequired
,指存储目标数字时需要用到的仓库数字数量。仓库数字是64位(位索引范围是0-63)long类型,则仓库第一个(索引为0)的仓库数字可以独立存储0-63的目标数字;当存储64-127时,则需要2个仓库数字;【有效数量】
wordsInUse
,指用来存储最大目标数字时所用的仓库数字的数量,也能表示BitSet能存储的数字的有效范围。例如,BitSet中存储了{1,60,120}三个数字,则有效数量就是用来存储120所用到的仓库数量,即2;2个有效仓库数字能存储0-127的数字,那么BitSet当前的有效范围就是[0, 128);
BitSet用64位二进制中每一位的索引来存储数字。例如,存储数字3,就将二进制中从右往左数的第3位设置成1。该二进制初始化时为64个0。
该二进制数转化成long类型的仓库数字存储在一个long数组中words
,即仓库。当存储的数字大于63(即超出了一个二进制long数据的长度)时,仓库就会新增一个仓库数字合作存储它。
对比传统的存储方式,一个数字(例如3)以int方式存储,需要4个字节32位;而利用BitSet,只需要1位即可表示该数字。
3 存储实现
3.1 set(int bitIndex)
步骤1:判断目标数字是否小于0:true-抛出异常,false-进入步骤2;
if (bitIndex < 0) throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
步骤2:计算存储了目标数字的位数据所在仓库数字的索引。例如,存储了60的位数据在索引为60/64=0的仓库数字中。
int wordIndex = wordIndex(bitIndex);
具体计算方法如下。因为仓库数字是long类型,长度为64位(2的6次方),目标数字作为索引不能超过这个长度,因此计算方式是目标数字除64取整,也即目标数字右移6位:
private static int wordIndex(int bitIndex) { return bitIndex >> ADDRESS_BITS_PER_WORD; // ADDRESS_BITS_PER_WORD=6}
步骤3:调整BitSet的有效范围。
expandTo(wordIndex);
步骤4:设置存储位。需要注意的是JAVA的位移操作,如果位移的位数大于数据类型的长度,JAVA并不会位移那么多位,而是只会位移位数%类型长度
的位数。例如,对1进行左位移120位操作时,实际只位移120%32=24位,其余补0;对1L进行左位移120位操作时,JAVA只位移120%64=56位,其余补0。
words[wordIndex] |= (1L << bitIndex);
例如,存储120时,第一个仓库数字不变,第二个仓库数字与2的56次方进行或操作,即将第二个仓库数字的第57位(下标为63+57=120)设置成1。
注意:之所以是63+57,是因为第一个仓库数字的索引是从0开始的,第64位的索引是63;而除第一个仓库数字之外的其他仓库数字的索引均是从1开始的,或者将他们单纯地理解为增量。
步骤5:检验。
private void checkInvariants() { assert(wordsInUse == 0 || words[wordsInUse - 1] != 0); assert(wordsInUse >= 0 && wordsInUse <= words.length); assert(wordsInUse == words.length || words[wordsInUse] == 0);}
expandTo()
确保BitSet的有效范围。如果有效数量小于的需求数量,则需提升BitSet的有效范围。
private void expandTo(int wordIndex) { // 需求数量:仓库数字索引+1 // 例如,目标数字为2,则仓库数字索引是2/64=0,需求数量是0+1=1,即只需要一个仓库数字就能存储目标数字2; // 同理,目标数字为67,则仓库数字索引是67/64=1,需求数量是1+1=2,即需要两个仓库数字才能存储目标数字67。 int wordsRequired = wordIndex+1; // 如果有效数量小于需求数量,表示目前有效仓库数字的数量不足以存储该数字,需提升有效仓库数字的数量 if (wordsInUse < wordsRequired) { ensureCapacity(wordsRequired); wordsInUse = wordsRequired; }}
ensureCapacity()
仓库words
自动扩容。执行到这儿,说明目标数字是当前BitSet存储的最大数字,有效数量无法满足存储该数字的需求,因此需要提升有效仓库数字的数量。
private void ensureCapacity(int wordsRequired) {}
如果仓库现有的长度不够,默认2倍递增;如果2倍依然不够,则以需求数量为扩容标准进行扩容。
例如,仓库当前长度是4,每个仓库数字是64位,如果目标数字是258,则wordRequired=258/64(=4)+1=5,仓库长度不够,默认按两倍扩容至8,能满足需求数量(5);如果目标数字是513,则wordRequired=512/64(=8)+1=9,仓库长度不够,默认2倍扩容至8,无法满足需求数量9,因此BitSet会扩容至9。
if (words.length < wordsRequired) { int request = Math.max(2 * words.length, wordsRequired); words = Arrays.copyOf(words, request);}
- java基础 ---- BitSet
- 【JAVA基础】BitSet
- Java BitSet
- java BitSet
- java bitset
- Java BitSet
- Java BitSet
- BitSet---Java!!!
- bitset基础用法+心得
- java中的BitSet学习
- java中的BitSet学习
- JAVA Bitset应用总结
- java中的BitSet学习
- java中的BitSet学习
- java.util.BitSet 分析
- java中的BitSet学习
- java bitSet的学习
- Java BitSet 找素数
- Java创建子类对象时的内存分配
- java作业
- C# 进程启动
- 创建一个slider UI,并将其呈现在世界坐标作为血条
- 一步一步创建GStreamer插件(ZZ)
- 【JAVA基础】BitSet
- 阶乘结果换算进制后得到数字的尾部有几个0
- Git和码云的使用
- threat
- 初识JVM(1)
- Spring Cloud 之服务注册中心高可用
- JavaScript简介及输出方式
- 9.密码翻译
- ETL流程概述及常用实现方法