一、Java常用小知识之将long型转换成字节表示

将long型转换成字节表示

/**
     * 将 long 类型数据转成二进制的字符串
     */
    private static String toFullBinaryString(long num) {
        //规定输出的long型最多有42位(00 00000000 00000000 00000000 00000000 00000000)
        final int size = 42;
        char[] chs = new char[size];
        for (int i = 0; i < size; i++) {
            /**
             * 目的:获取第i位的二进制数
             * 解析:
             *     ((num >> i) & 1):
             *     因为1的二进制的特殊性(0000 0001),在进行“&”运算时,只有末位会被保留下来(比如,末位为“1”,运算
             * 后为1;末位为0,运算后为0),其他位置全部被置为0。
             *     这样当需要将一个整型转换成二进制表示时,需要取出每个位置的二进制数值(1或者0),那么就可以右移该位置
             * 数,与“1”进行“&”运算。
             *     比如:取出3(0000 0011)的第2位(也就是1),则右移1位--》得到“0000 0001”,然后与1(“0000 0001”)
             * 进行“&”运算,得到“1”。以此类推即可得到每个位置为二进制数
             *     “((num >> i) & 1) + '0'”:
             *     字符‘0’的“ASCLL”码对应的数值为48,比如"(char) (49)"那么计算字符的方法就是:49-48 = 1,所以对应的
             * 字符就是'1',所以“((num >> i) & 1) + '0'”这段代码的意思就是,取出“num”二进制时对应的每个位置数值(只能
             * 为“0”或“1”,不过此时还是二进制表示法:0 0000 0000 ; 1 0000 0001)。之后,与字符'0'对应的数值“48”进行
             * 加运算,结果只能为(48 或者 49),再经过(char)强转后(“char”强转就是根据传入的数值,与“48”进行比较,
             * 比如“49”,多1,那么对应的字符就是“1”),就变成了字符,“0”或者“1”,就取出了特定位置的二进制数值
             *
             */
            chs[size - 1 - i] = (char) (((num >> i) & 1) + '0');
        }
        return new String(chs);
    }

应用

签到历史:
“签到历史”要实现的效果:
* 签到历史为整数。将整数转化为2进制数,1表示签到,0表示未签到
* 例如:
* 签到历史为3(11)时,则表示用户从第一次签到导现在为止连续签到两天。
* 签到历史为5(101)时,则表示第二天未签到
* 签到历史为25(11001)时,则表示第二天和第三天未签到

实现代码

public class SignInHistoryTool {
    /**
     * 计算签到历史记录
     * 签到历史
     * 签到历史为整数。将整数转化为2进制数,1表示签到,0表示未签到
     * 例如:
     * 签到历史为3(11)时,则表示用户从第一次签到导现在为止连续签到两天。
     * 签到历史为5(101)时,则表示第二天未签到
     * 签到历史为25(11001)时,则表示第二天和第三天未签到
     *
     * oldHistory << moveAmount 向左位移未签到天数
     * @param oldHistory 上次签到的数值
     * @param moveAmount 中间未签到的天数
     * @return
     */

    public static int historyDays(int oldHistory, int moveAmount) {
        /*
         * 重置签到历史记录(积分,连续打卡记录不清除)
         * 条件:每个月的月初重置一次
         */
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        if (dayOfMonth == 1){
            oldHistory = 0;
            moveAmount = 1;
        }
        //(比如:0000 0011 2天)
        /*
         * 若“moveAmonut = 1”:属于正常的隔天签到
         * 若“moveAmonut = 2”:属于隔1天签到
         */
        long moveResult = oldHistory << moveAmount;
        /*
         *  将本次签到放到最后一位
         */
        moveResult +=1;
        /*
         * 将 long 类型数据转成二进制的字符串
         * 参数一:将 long 类型数据转成二进制的字符串
         * 参数二:该字符串的进制(是2进制,还是8进制之类)
         */
        return Integer.parseInt(toFullBinaryString(moveResult), 2);
    }

    /**
     * 将 long 类型数据转成二进制的字符串
     */
    private static String toFullBinaryString(long num) {
        //规定long型最多有42位(00000000 00000000 00000000 00000000 00000000 00000000)
        final int size = 42;
        char[] chs = new char[size];
        for (int i = 0; i < size; i++) {
            /**
             * 目的:获取第i位的二进制数
             * 解析:
             *     ((num >> i) & 1):
             *     因为1的二进制的特殊性(0000 0001),在进行“&”运算时,只有末位会被保留下来(比如,末位为“1”,运算
             * 后为1;末位为0,运算后为0),其他位置全部被置为0。
             *     这样当需要将一个整型转换成二进制表示时,需要取出每个位置的二进制数值(1或者0),那么就可以右移该位置
             * 数,与“1”进行“&”运算。
             *     比如:取出3(0000 0011)的第2位(也就是1),则右移1位--》得到“0000 0001”,然后与1(“0000 0001”)
             * 进行“&”运算,得到“1”。以此类推即可得到每个位置为二进制数
             *     “((num >> i) & 1) + '0'”:
             *     字符‘0’的“ASCLL”码对应的数值为48,比如"(char) (49)"那么计算字符的方法就是:49-48 = 1,所以对应的
             * 字符就是'1',所以“((num >> i) & 1) + '0'”这段代码的意思就是,取出“num”二进制时对应的每个位置数值(只能
             * 为“0”或“1”,不过此时还是二进制表示法:0 0000 0000 ; 1 0000 0001)。之后,与字符'0'对应的数值“48”进行
             * 加运算,结果只能为(48 或者 49),再经过(char)强转后(“char”强转就是根据传入的数值,与“48”进行比较,
             * 比如“49”,多1,那么对应的字符就是“1”),就变成了字符,“0”或者“1”,就取出了特定位置的二进制数值
             *
             */
            chs[size - 1 - i] = (char) (((num >> i) & 1) + '0');
        }
        translate(chs);
        return new String(chs);
    }

    /**
     * 将得到的二进制数组倒置
     * 例:
     *     第1天、第2天签到:0000 0011
     *     第3/4天未签到,第五天签到,则先左移2位,再末位加1:0001 1001
     *     将得到的二进制数组倒置:00010011(即变成第1、2天签到,第3、4天未签到)
     * @param chs 二进制数组
     */
    private static void translate(char[] chs) {
        int reverseIndex = 0;
        for (int i = 0; i < chs.length; i++){
            if (!String.valueOf(chs[i]).equals("0")){
                reverseIndex = i;
                break;
            }
        }
        if (reverseIndex != 0){
            swap(chs, reverseIndex, chs.length-1);
        }
    }

    private static void swap(char[] chs, int startIndex, int endIndex) {
        if (chs == null || chs.length==0 || startIndex >= chs.length || endIndex >= chs.length){
            return;
        }
        if (startIndex < 0){
            startIndex = 0;
        }
        if (startIndex >= endIndex){
            return;
        }
        int middleIndex = (endIndex - startIndex) / 2;
        if ((endIndex - startIndex) % 2 == 1){
            middleIndex+=1;
        }
        for (int i = 0; i < middleIndex; i++){
            char temp = chs[startIndex+i];
            chs[startIndex+i] = chs[chs.length-1-i];
            chs[chs.length-1-i] = temp;
        }
    }

    /**
     * 计算距离上一次签到,相隔天数
     * @return
     * @throws ParseException 
     */
    public static int countSignDays(Date nowDate,Date lastModifyDate) throws ParseException{
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String lastDateStr = df.format(lastModifyDate);
        Date lastDate = df.parse(lastDateStr);
        // 这样得到的差值是微秒级别
        long diff = nowDate.getTime() - lastDate.getTime();
        int days = (int) (diff / (1000 * 60 * 60 * 24));
        if (days == 0){
            //与当天24点比较,有没有过24点,过了,不足1天,按1天算
            days = compare(nowDate, lastModifyDate);
        }
        return days;
    }

    /**
     * 若当前签到时间过了前一天的24点,也算隔1天
     * @param nowDate 当前签到时间
     * @param lastModifyDate 上次签到时间
     * @return 若当前签到时间过了前一天(也就是上次签到)的24点,也算隔1天,可以签到;否则不可以签到
     */
    private static int compare(Date nowDate, Date lastModifyDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(lastModifyDate);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 9999);
        return nowDate.getTime() > calendar.getTimeInMillis() ? 1 : 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值