java long 详解_Java——long值进行Base64编码原理详解

long值进行Base64编码原理详解

分析一下long值;

1、有符号long值,64bit,8字节,取值范围-2^63——2^63-1,第一位符号位,负数为1,正数为0;

2、正数,符号位0,后63位为正数值;

3、负数,符号位1,整个64位取反、加1,加负号即为负数值;

Base64是做什么?

把任意二进制数据转换为可显示字符,总共64种可显示字符。

具体转换规则为每6个bit为一段,映射为一个可显示字符,总bit数不能被6整除的,后面补0,且只能按

整字节补,即每次至少补8个bit,直到能被6整除。

6bit与可打印字符的转换规则为:

12450948e8c233be1fa2bdef26dc1997.png

最后两个字符特殊,或是URLEcoder可换成"-" "_"。另,末尾补的0通常不记成A,而记为=。

Java中的Base64算法。

早期jdk提供的sun.misc.BASE64Encoder;

apache提供的org.apache.commons.codec.binary.Base64;

jdk8内置的java.util.Base64;效率高一些。

回归题目。long值进行Base64编码。

1、今有long值0,左移11位+1,再左移5位+1,再左移42位+1,得

二进制数  0000 0100   0000 0000   1000 0100   0000 0000   0000 0000   0000 0000  0000 0000   0000 0001

16进制数  400840000000001

十进制数  288375511686578177

2、把该二制long值转为长度为8的byte数组,

[4, 0, -124, 0, 0, 0, 0, 1]

其中注意-124的由来,“1000 0100”取反+1得,0111 1100,即为-124。

3、由于该byte数组,并不是每个元素都能对应 ASCII编码中的可打印字符,所以即使把byte数据转成字符串类型可无法打

印出来,强行打印会打出

59949c923b4c21e37c04f053336084c0.png

4、把该byte数组进行Base64编码,Base64.getUrlEncoder().encode(uidBytes)得到编码后byte数组

[66, 65, 67, 69, 65, 65, 65, 65, 65, 65, 69, 61]

编码byte数组长度为12,因为8*8=64,可转10段6bit,剩4bit,补1字节即8bit,多出2段6bit,总个12段6bit;

编码byte数组,每个元素均能对应ASCII编码中的可打印字符,按ASCII编码打印得

BACEAAAAAAE=

5、以上过程逆向运算,仍能把BACEAAAAAAE=转成原来的long值;

6、附上ASCII编码表

db5085264d604cfd1d4d8e5adfea746b.png

以上过程用java代码实现如下:

public voidtestBase64() throws Exception {

Long uid= 288375511686578177L;

LOGGER.info(String.valueOf(uid));

LOGGER.info(Long.toHexString(uid));

LOGGER.info(Long.toBinaryString(uid));

String uidstr=String.valueOf(uid);byte[] bytes =uidstr.getBytes();byte[] encodeBytes =Base64.getEncoder().encode(bytes);

String encode= new String(encodeBytes, "UTF-8");

LOGGER.info(encode);

LOGGER.info(Base64.getEncoder().encodeToString(bytes));byte b = 0;char bb = '0';short ss = (short) bb;byte[] uidBytes = new byte[8];for (int i = 0; i < uidBytes.length; i++) {

uidBytes[i]= (byte) (uid >> (8 * (8 - 1 -i)));

}//uidBytes[0] = (byte)(uid >> (8*7));

LOGGER.info(new String(uidBytes, "UTF-8"));byte[] encodeUid =Base64.getUrlEncoder().encode(uidBytes);

String dstUid= new String(encodeUid, "UTF-8");

LOGGER.info(dstUid);//dstUid = "BACEAAAAAAcA";

byte[] decodeUid =Base64.getUrlDecoder().decode(dstUid.getBytes());long rsUid = 0L;for (int i = 0; i < decodeUid.length; i++) {long temp = decodeUid[i] & 0xFF; //把有符号扩大为无符号

rsUid += temp << (8 * (8 - 1 -i));

}

LOGGER.info(String.valueOf(rsUid));

LOGGER.info(Long.toHexString(rsUid));

}

生成long的代码如下:

public intinitId() {//初始化id的规则如下://最高1bit符号位+5bit区域编号(1~32)+11bit服务器编号(1~2048)+5bit服务编号(1~32)+42bit自增数据//最高1bit符号位

long min = 0;//5位区域编号

min = min +1;//11位服务器编号

min = min << 11; //左移11位 给serverId空出11个位置 共1~2048个

min = min +1;//5位服务编号

min = min << 5; //左移5位 给servicesId空出5个位置 共1~32个

min = min +1;//42bit自增数据

min = min << 42; //左移42位 给表主键空出42个位置 共1~10^42个//最后64-42-5-11=6,剩下的首部6位,区域编号显5个,最首部1位是符号位

return min;}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值