将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;
}
}