java BitSet

本文详细探讨了Java中的BitSet类,解释了其设计理念和内部工作机制,包括如何存储和操作二进制数据,以及toString方法的巧妙实现。文章还介绍了如何查找第一个和剩余的标志位,并鼓励读者深入研究BitSet的其他功能。
摘要由CSDN通过智能技术生成

写在前面

未经允许不得转载!

java.util.BitSet 这个类其实很简单,但是我觉得很有意思,所以专门写篇文章说下怎么个有意思法!

进入正题

首先从名字上大致就知道这个类是干嘛的,存储 Bit 的 Set,Bit 就是二进制数据01(理解成标志位就行,0没有,1有),而Set就是数学中的那个Set(集合),自己查资料。
拓展点:BitMap,有兴趣自己查资料。

先说下我是怎么理解 BitSet 设计理念的:

先开辟一块连续的内存(long 数组),因为long占64个bit,所以数组的每个格子就是64个bit。

private long[] words;

找到对应的数组的格子,即找到数组的下标。要设置0到63号标志位的,定位到数组的下标是0,64到127定位到数组的下标是1,依此类推,简单说找下标就是位置x/64。

int wordIndex = wordIndex(bitIndex);

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

计算出并拿到指定编号位置设置标志位的值。上面说的数组的下标找到了,但是怎么设置一个bit位呢,long不是占64个bit吗?这里开始就有点意思了,比如说我要设置56号的标志位为1,那么我只要在long的64位中的第56号位设置为1就行了,这时需要用到移位操作,理论上有两种移动方式(1L<<55和Long.MIN_VALUE>>55),BitSet的设计者使用的是1向左移。为什么我说有意思呢?想想上一步找到数组的下标,比如2在数组的下标是0,56在数组的下标是0,65在数组的下标是1。同时long的左移操作是周期性的(具体查看 jvm 规范的 lshl 指令的描述及Notes,看完再看后面那句你就懂了),简单说就是:x & 0x3f,因为63有效位的二进制全是1,所以等价于 x%64。

(1L << bitIndex)

我不知道到读者有没有想明白这两步,简单说下吧,后面还会涉及到,如果没搞明白后面可能会懵逼:
假设有一块连续的内存,按 bit 存,上面的所有数据都是0,然后我们把他按照64个bit一个进行等分,此时懂 long 数组的意思了吧!
然后以数组的第0个下标(一个 long 值,64个bit位)为坐标轴原点,这时就知道每个数组下标对应的bit位的范围了,比如第0个下标就是0-63,第一个就是64-127,依此类推。
然后以64个bit位的第0个bit位为坐标轴原点,这时就能精确定位到指定的bit位了。

首次设置bit标志位。将上一步拿到的指定编号位置设置标志位的值直接赋值到数组的指定位置的下标就行了。

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

同个数组下标位置非首次设置bit标志位。上面说的只是数组的某个格子第一次设置值,如果有第二次设置的话还是这么操作的话就会被覆盖了,这时就需要按位或操作了,比如说第1次设置56号的标志为1,计算出并拿到指定编号位置设置标志位的值是(1L<<55),然后根据首次设置bit标志位的操作,将其赋值给数组的0下标;然后第2此设置21号的标志为1,计算出并拿到指定编号位置设置标志位的值是(1L<<20) ,这时就不能直接给赋值给数组的0下标了,而是要进行按位或((1L<<20) | (1L<<55))第21、56号都为1了,然后赋值给数组的0下标。

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

查询指定指定bit位是否为1。比如说21号,首先先找到数组的下标(看前面说,找到的下标为0),计算出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值