java中BitArray用来模拟时间序列或位图等功能

业务需求需要一种类似redis的bitmap的数据结构,java中有bitArray,但是功能不够全,需要一种移位操作,即,每一秒都把BitArray右移一位,下面来实现,整体感觉跟hashmap arraylist都差不多,顺便多写点注释:

其实经过测试可以知道,对于实现随着时间每一秒推移追加一个bit位的操作,历史记录时间在60s内最好用long的移位直接实现,简单也最高效,但超过long的64位上限就不行了,其次是boolean[]不停的arrayCopy和set,速度慢一点空间占用多一点,最后才是下文代码中的tailSet方法,复杂度高慢的明显但占用空间少。需要综合考虑场景,最好用long直接实现

即:
long l = (l<<1)|1;
代表了时间过了1s,新来的数据标记为1,表示存在数据,超级简单快

//可以继承security包下的BitArray,很多方法用父类,简介
//这里便于理解,部分简单方法直接从源码copy,不继承
//新增了一个成员变量capacity,因为移动意味着实际容量会减少
public class BitArray1 {

    // 存储真正的二进制数据
    private byte[] repn;
    private int length; //整个数据结构的长度
    private int capacity;//当前已使用的容量

    public BitArray1(int var1) throws IllegalArgumentException {
        if (var1 < 0) {
            throw new IllegalArgumentException("Negative length for BitArray");
        } else {
            this.length = var1;
            this.repn = new byte[(var1 + 8 - 1) / 8];
        }
    }


    // subscript下标,返回这个位置应该有多少个整的byte
    private static int subscript(int var0) {
        return var0 / 8;
    }

    //返回var0 在一个byte内应处的位置,从右往左走的,也就是一个byte内的应有的二进制表示
    private static int position(int var0) {
        return 1 << 7 - var0 % 8;
    }

    //var1 要放置的位置,var2放置true还是false

    /**
     * copied from BitArray source code
     *
     * @param var1 位置
     * @param var2 true false
     * @throws ArrayIndexOutOfBoundsException
     */
    public void set(int var1, boolean var2) throws ArrayIndexOutOfBoundsException {
        // 容量范围内
        if (var1 >= 0 && var1 < this.length) {
            int var3 = subscript(var1);//从前面数第几个完整的byte
            int var4 = position(var1);//最后一个不完整byte 从前面数的位置
            byte[] var10000;
            if (var2) {
                var10000 = this.repn;
                var10000[var3] = (byte) (var10000[var3] | var4);// 取出对应区域8位byte表示,var4肯定只有一个1,或运算,将对应位置置为1
            } else {
                var10000 = this.repn;
                var10000[var3] = (byte) (var10000[var3] & ~var4);
                // 取反,var4目标位置变为0,其他位置变为1,与上对应位置的byte var3,
                // 原有1才变成1,原有0还是0,目标位置不管原有1还是0都变成0
            }

            this.capacity++;

        } else {
            throw new ArrayIndexOutOfBoundsException(Integer.toString(var1));
        }
    }

    /**
     * 整体右移offset位,基于byte[]实现
     * 如果长度不是很大的情况,使用long[]会更加简单
     *
     * @param offset
     */
    public void rightMove(int offset) {
        //实际上,右移仍然要保证this.repn的首元素byte为8个字节,而不是保证尾元素为8个字节

        if (offset > 0 && offset < this.length) {
            int var1 = offset / 8; // offset要移动var1个完整8位byte
            // repn 从后面数,剔除 var1个byte
            byte[] temp = new byte[this.repn.length - var1];
            System.arraycopy(this.repn, 0, temp, 0, this.repn.length - var1);
            //新的 最后byte有var3个数,下标应该截止到var3-1,也就是temp要截止到var3-1 取到
            int var2 = (this.length - offset) % 8;
            int var3 = ~(127 >> (var2 - 1)); // 后5位1 取反后变前面全1 后面0
            temp[temp.length - 1] = (byte) (temp[temp.length - 1] & var3);
            // 赋值并修改长度
            this.repn = temp;
            this.length -= offset;
        } else {
            //offset大于整体长度直接变成全0了,没有实际意义
            throw new ArrayIndexOutOfBoundsException(Integer.toString(offset));
        }

    }
    

    /**
     * 特定用途: 左移一位,并且将最后的空位 置为b
     *
     * @param b
     */
    public void tailSet(boolean b) {
        //1.没满的时候,直接往后面加
        if (this.capacity < this.length) {
            this.set(this.capacity, b);
        } else {
            //2.满了以后,全体左移1位并set
            for (int i = 0; i < this.repn.length - 1; i++) {
                //2.1 遍历,每次当前byte左移,然后取下一byte首位补足
                repn[i] = (byte) ((repn[i] << 1) + (repn[i + 1] & (1 << 7)));
            }
            //2.2 最后一byte左移,并取入参补足,注意空的地方肯定是0,所以else不用动

            repn[repn.length - 1] = (byte) (repn[repn.length - 1] << 1);

            if (b) {
                repn[repn.length - 1] = (byte) (repn[repn.length - 1] | (1 << (8 - capacity % 8)));
            }
        }
    }

    public boolean get(int var1) throws ArrayIndexOutOfBoundsException {
        if (var1 >= 0 && var1 < this.length) {
            return (this.repn[subscript(var1)] & position(var1)) != 0;
        } else {
            throw new ArrayIndexOutOfBoundsException(Integer.toString(var1));
        }
    }

    public boolean[] toBooleanArray() {
        boolean[] var1 = new boolean[this.length];

        for (int var2 = 0; var2 < this.length; ++var2) {
            var1[var2] = this.get(var2);
        }

        return var1;
    }


}

版权声明:本文为u012496112原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。