博客搬家啦,更多干活 https://blog.csdn.net/qq_2816...

最近在tcp的基础上写一个自定义的协议,处理拆包粘包的时候发现一个情况

数据是以字节流的形式在tcp中传输,所以,大于一个字节的数据类型,都要转为byte[] 的形式

以int类型举例,在java中一个int类型的数据占4个字节,也就是需要new byte[4]

        int a = 9071;
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (a >> 24 ); //  拿到最高位的8位
        bytes[1] = (byte) (a >> 16 );
        bytes[2] = (byte) (a >> 8 );
        bytes[3] = (byte) (a);

java中的数据类型都是有符号类型,也就是说区分正负的

一个字节=8bit,也就是说一个 byte 可以存放8个 0 或者 1

1 的二进制原码是 0 000 000 1
-1 的二进制原码是 1 000 000 1,补码是 1111 1111

二进制的最高位为符号位,所以byte 的取值范围为-128~127,(-2^7~2^7-1)

在 Java 中,是采用补码来表示数据的。

正数的补码和原码相同,负数的补码是在原码的基础上各位取反然后加 1。

譬如:int a = -29 的二进制表示为11111111111111111111111111100011

int 32字节,先取a的的绝对值求原码,29 的原码为00011101

不足4字节,高位补24个0

00000000000000000000000000011101

再求反码

11111111111111111111111111100010

+1
于是得到了-29的二级制补码

11111111111111111111111111100011

通过上面的代码看,int 在tcp传输的时候要转换为byte[], int a = -29; 一共4个字节32位,于是byte[4] 每一个小标存储一个字节也就是8位,写到这里我们发现还是用不上&0xff,不要着急,接下来就用上了

于是,我们发现int 29 被装进 byte[] 的时候,成了这个样子:

下标0表示的是前8位,
下标1表示的是8-16位,
下标2表示的是16-24位,
下标3表示的是24-32位

也很容易理解,因为-1的补码就是 11111111 ,所以这4个byte的二进制组合起来就是int -29 的二进制

image.png

你把数据拆开了还要把它组合起来啊,也就是byte[] 转 int

分解问题就是单个byte 转 int

byte 八个字节,int 32个字节,byte为负数的时候,需要把高24位的全部置为0.保持低八位的一致性,不然得到的int就成了另一个数字

0xff 是16进制,也就是255 二进制也就是 1111 1111
补到32位也就是 这里是24个0 这里是八个1
一个负数的byte & 0xff的时候,高24位就成了0,保证了一致性
然而正数的补码还是它自己,不受影响,虽然只有负数的时候才需要 &0xff,但不至于再判断一次去吧?


Devilu
85 声望4 粉丝

just a newbie