java之简易bitmap实现

当需要用比较少的空间存储true和false时,不防考虑下通过bitmap实现。

bitmap用途还是非常广泛的,比如布隆过滤器等。

下面介绍如何用java实现一个bitmap用于存储状态数据(0/1、true/false)

public class BitMap {

    /**
     * 二进制数据存储,存储内容为[0,0,1,1]
     */
    char[] binaryChars = null;

    /**
     * 扩张因子,当binaryChars小时,以该值扩张
     */
    private static final double DILATATION_FACTOR = 1.3;

    /**
     * defaultChar 无状态时的值  因为存的为0,1所以无状态即为0
     */
    private char defaultChar = '0';
    /**
     * valueChar 有状态时的值  因为存的为0,1所以无状态即为1
     */
    private char valueChar = '1';

    /**
     * 将字符串转为BitMap
     *
     * @param data
     */
    public BitMap(String data) {
        // 转换为整数  Long大小有限制  使用bigInteger  无大小限制
        BigInteger number = new BigInteger(data);
        //转换为二进制
        String binaryString = number.toString(2);
        //转换为二进制字符数组
        binaryChars = binaryString.toCharArray();
    }

    /**
     * 创建大小为位数size的二进制
     * 大小为size bitmap,使用set时index最大为size-1,否则会触发扩容
     *
     * @param size
     */
    public BitMap(int size) {
        binaryChars = new char[size];
        for (int i = 0; i < binaryChars.length; i++) {
            binaryChars[i] = defaultChar;
        }
    }

    /**
     * 默认10size
     */
    public BitMap() {
        this(10);
    }

    /**
     * 返回当前数组长度 
     * 与 toString后生成的字符串的长度不同,toString会trim左边的0
     * @return
     */
    public int size() {
        return binaryChars.length;
    }



    /**
     * 对坐标赋值
     *
     * @param index 位置,从数组的右边开始向左递增,防止转为bigInteger时,省掉右边的0导致数据问题
     * @param value true or false
     */
    public void set(int index, boolean value) {
        if (index >= binaryChars.length) {
            //扩容
            dilatation(index);
        }
        //从低位开始存,为了防止转数字时,丢掉高位
        binaryChars[binaryChars.length - 1 - index] = value ? valueChar : defaultChar;
    }

    /**
     * 扩容
     *
     * @param size 以size计算扩容后的数组大小
     *             取+10 & *DILATATION_FACTOR 中的小值
     */
    private void dilatation(int size) {
        int max = Math.min(size + 10, (int) (size * DILATATION_FACTOR));
        char[] temp = new char[max];
        //从右边数据开始迁移到新的数组,如果不存在则置为defaultChar
        for (int i = 0; i < temp.length; i++) {
            if (i < binaryChars.length) {
                temp[temp.length - 1 - i] = binaryChars[binaryChars.length - 1 - i];
            } else {
                temp[temp.length - 1 - i] = defaultChar;
            }
        }
        binaryChars = temp;
    }

    /**
     * 获取第index坐标上是否有值
     *
     * @param index
     * @return
     */
    public boolean get(int index) {
        //如果该坐标大于了binaryChars.length则表示未存储,返回false
        if (index >= binaryChars.length) {
            return false;
        }
        //is equal valueChar
        return binaryChars[binaryChars.length - 1 - index] == valueChar;
    }

    /**
     * 转为string,通过BigInteger转时会丢掉左侧的0
     *
     * @return
     */
    public String toString() {
        BigInteger num = new BigInteger(new String(binaryChars), 2);
        return String.valueOf(num);
    }

    /**
     * toString
     * @param radix 进制 如2
     * @return
     */
    public String toString(int radix){
        BigInteger num = new BigInteger(new String(binaryChars), 2);
        String binaryString = num.toString(radix);
        return binaryString;
    }
    
    public static void main(String[] args) {
        BitMap bitMapUtil = new BitMap(10);
        bitMapUtil.set(0, true);
        System.out.println(bitMapUtil);

        bitMapUtil = new BitMap(bitMapUtil.toString());
        bitMapUtil.set(11, true);
        System.out.println(bitMapUtil);
        System.out.println(bitMapUtil.get(11));
        System.out.println(bitMapUtil.get(10));
        System.out.println(bitMapUtil.get(100));
        bitMapUtil.set(11, false);
        System.out.println(bitMapUtil);
    }
}