基础数据与byte间的转化

基础知识

计算机中存储是用补码!!,同时注意一下计算省略了高位不变部分和 字节大小端问题

基础数据

  • byte:有符号,在网络传输中都是会用到byte的,它占1个字节,共8位,比如说11111111就可以用1个
    byte表示,转化为10进制:- (2的6次+2的5次+2的4次+2的3次+2的2次+2的1次+2的0次) = -127。
    其中前7位表示数字,最高位表示符号,0为正,1为负。范围是 (-2的7次 ~ 2的7次 - 1),那为什么前
    面最小是-127,范围最小又是-128呢?因为规定-0(10000000)为-128。
  • short:有符号,占2个字节,共16位。同byte一样,它的取值范围就是 (-2的15次 ~ 2的15次 - 1)。
  • int:有符号,占4个字节,共32位。它的取值范围就是(-2的31次 ~ 2的31次)。
  • long:有符号,占8个字节,共64位,它的取值范围就是(-2的63次 ~ 2的63次)。

位运算

  • ^:表示异或位运算,两者相同则为0,两者不同则为1。比如说15^2,15用二进制表示就是1111,2用2
    进制表示就是0010,两者进行异或运算,结果就是1101,转换为十进制就是13。
A B A^B
1 1 0
1 0 1
0 1 1
0 0 0
  • |:表示或运算,两者只有有一个为1就为1, 比如说13|2,13用二进制表示就是1101,2用二进制表示
    就是0010,两者进行或运算,那么结果就是1111,转换为十进制就是15。
A B A | B
1 1 1
1 0 1
0 1 1
0 0 0
  • &:表示与运算,两者都为1就为1,其余都为0,比如说15&2, 13用二进制表示就是1111,2用二进制
    表示就是0010, 两者进行与运算,那么结果就是0010,转换为十进制就是2。
A B A&B
1 1 1
1 0 1
0 1 1
0 0 0
  • ~:取反,就是本来是0变成1,本来是1变成0。
A ~A
1 0
0 1
  • <<:左移运算符,不需要考虑符号位,因为在后面补0,把二进制的数字向左移动,低位补0。比如说 3<<2。
    3的二进制码为11,向左移动2位就是1100,那么结果就是12。

  • >>:右移运算符,带符号位。根据这个要移动的数字决定正负,如果是正数,那么就在前面补0,如果是
    负数就在前面补1。比如说 3>>2,3的二进制码为00000011,向右移动2位,就变成00000000,转化为十
    进制就是0了(3是正数所以在高位补0)。再比如说-3>>2,-3的二进制码为10000011,转化为补码
    (只要涉及到负数,就需要转换到补码计算,正数之所以不用转化,是因为他们的补码和原码是一致的)
    11111101,进行位移运算,就是11111111,这个是补码,需要再转回原码。那么就是取反+1,结果就是
    10000001,转化为十进制就是-1。

  • >>>:右移运算符,与上面的区别就是这个运算符是 无符号的。不论正负,高位都补0。如果要用
    -3>>2来验证,因为高位补0,就需要把所有的位数都写全了。如果是int,那就要写成32位来运算。切记切记。
    上面很多因为高位的变化“取反再取反”会导致前面所有的位都没变所以我就简化了,但是这个>>>运算符不行哦,
    它会把负数变为正数。

栗子(eg):
比如说-15|3等于多少呢?有些人会觉得-15转化为二进制就是10001111,而3转化为二进制就是00000011,
那么结果应该是10001111呀,转换为十进制就是-15呀?大家可以自己写个demo就会发现是不对的。要注意
在计算机中所有的都是用补码的形式存储的,之所以上面介绍两个正数是对的,因为 正数的反码和补码都是一样的。而负数求补码应该是除去符号位取反+1,我们再来看看这个题-15|3,其中-15的原码为10001111,反码为11110000,那么补码就是11110001,然后3的补码为00000011,两者进行或操作就是11110011,你以为结束了么?还没有,再又要求它的原码了,原码就是补码再求补码再+1(是不是已经晕掉了?),也就是
10001101,结果就是-13。为了大家都好理解,我这里用算式整理一下:

求 -15|3

[-15]原码 = 10001111
[-15]反码 = 11110000 //原码求反码符号位不变
[-15]补码 = 11110001 //反码+1等于补码

[3]原码 = 00000011
[3]反码 = 00000011 //正数都一致
[3]补码 = 00000011 //正数都一致

-15|3 = 11110011 //两个补码进行或操作

[结果]补码 = 11110011 //上面求得的值
[结果]反码 = 10001100 //符号位不变
[结果]原码 = 10001101 //反码+1

100001101 转化为十进制就是-13。
不知道我这么解释会不会更加清楚一些呢?同理的,上面那些(尤其是求反‘~’我故意没写例子,大家自己去试试吧)。

在说一次,正数的原码,补码,反码都一样,如果一定要说为什么一样,我就举个例子。有这么一个等式7+(-7)=0。
我们知道
[-7]原 = 10000111
[-7]反 = 11111000
[-7]补 = 11111001

那么如果要存在一个值和[-7]补码相加等于0,是不是就是00000111!!所以正数的补码和原码是一致的。
这样解释虽然怪怪的,但是可以知道的确是这样的。

代码实现

基本步骤:
① 分析转化和代转化之间位数的关系
② 计算偏移量。每次都取最后8位
③ 把最后8位和0xff进行&操作
④ 得出结果。

有人会问,为什么要和0xff进行&操作?这里解释下,因为再分割的时候,我们要保证最后8位是一致的,更高位都要置0,这样才能保证数据的一致性。比如说由byte转化成short。位数从8位变成了16位,那么在计算机自己看来,它会把前面多出来的8位置1。而&0xff就可以把前面所有的位数都置0。

  1. short与byte的相互转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/**
* 前提:在计算机中所有的都是用补码的形式存储的。
* 将short转换为字节
*
* 例如 8的补码为0000 0000 0000 1000,所以要将转换为两个字节,第一个字节是将8右移8位然后和0x00ff求与,
* 而第二个字节则是右移0位,然后求与
*/
public static byte[] short2byte(short s){
byte[] b = new byte[2];
for(int i = 0; i < 2; i++){
int offset = 16 - (i+1)*8; //因为byte占1个字节,所以要计算偏移量
b[i] = (byte)((s >> offset)&0xff); //把16位分为2个8位进行分别存储
}
return b;
}

public static short byte2short(byte[] b){
short l = 0;
for (int i = 0; i < 2; i++) {
l<<=8; //<<=和 +=是一样的,意思就是 l = l << 8
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
}
return l;
}
  1. int与byte的相互转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static byte[] int2byte(int s){
byte[] b = new byte[2];
for(int i = 0; i < 4; i++){
int offset = 16 - (i+1)*8; //因为byte占1个字节,所以要计算偏移量
b[i] = (byte)((s >> offset)&0xff); //把32位分为4个8位进行分别存储
}
return b;
}


public static int byte2int(byte[] b){
int l = 0;
for (int i = 0; i < 4; i++) {
l<<=8; //<<=和 +=是一样的,意思就是 l = l << 8
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
}
return l;
}
  1. long与byte的相互转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* @方法功能 字节数组和长整型的转换
* @param 字节数组
* @return 长整型
*/
public static byte[] longToByte(long number) {
long temp = number;
byte[] b = new byte[8];
for (int i = 0; i < b.length; i++) {
b[i] = new Long(temp & 0xff).byteValue();
// 将最低位保存在最低位
temp = temp >> 8;
// 向右移8位
}
return b;
}

/**
* @方法功能 字节数组和长整型的转换
* @param 字节数组
* @return 长整型
*/
public static long byteToLong(byte[] b) {
long s = 0;
long s0 = b[0] & 0xff;// 最低位
long s1 = b[1] & 0xff;
long s2 = b[2] & 0xff;
long s3 = b[3] & 0xff;
long s4 = b[4] & 0xff;// 最低位
long s5 = b[5] & 0xff;
long s6 = b[6] & 0xff;
long s7 = b[7] & 0xff; // s0不变
s1 <<= 8;
s2 <<= 16;
s3 <<= 24;
s4 <<= 8 * 4;
s5 <<= 8 * 5;
s6 <<= 8 * 6;
s7 <<= 8 * 7;
s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
return s;
}
  1. char与byte的转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 字符到字节转换
*
* @param ch
* @return
*/
public static void putChar(byte[] bb, char ch, int index) {
int temp = (int) ch;
// byte[] b = new byte[2];
for (int i = 0; i < 2; i ++ ) {
bb[index + i] = new Integer(temp & 0xff).byteValue(); // 将最高位保存在最低位
temp = temp >> 8; // 向右移8位
}
}

/**
* 字节到字符转换
*
* @param b
* @return
*/
public static char getChar(byte[] b, int index) {
int s = 0;
if (b[index + 1] > 0)
s += b[index + 1];
else
s += 256 + b[index + 0];
s *= 256;
if (b[index + 0] > 0)
s += b[index + 1];
else
s += 256 + b[index + 0];
char ch = (char) s;
return ch;
}
  1. float与byte的转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* float转换byte
*
* @param bb
* @param x
* @param index
*/
public static void putFloat(byte[] bb, float x, int index) {
// byte[] b = new byte[4];
int l = Float.floatToIntBits(x);
for (int i = 0; i < 4; i++) {
bb[index + i] = new Integer(l).byteValue();
l = l >> 8;
}
}

/**
* 通过byte数组取得float
*
* @param bb
* @param index
* @return
*/
public static float getFloat(byte[] b, int index) {
int l;
l = b[index + 0];
l &= 0xff;
l |= ((long) b[index + 1] << 8);
l &= 0xffff;
l |= ((long) b[index + 2] << 16);
l &= 0xffffff;
l |= ((long) b[index + 3] << 24);
return Float.intBitsToFloat(l);
}
  1. double与byte的转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* double转换byte
*
* @param bb
* @param x
* @param index
*/
public static void putDouble(byte[] bb, double x, int index) {
// byte[] b = new byte[8];
long l = Double.doubleToLongBits(x);
for (int i = 0; i < 4; i++) {
bb[index + i] = new Long(l).byteValue();
l = l >> 8;
}
}

/**
* 通过byte数组取得float
*
* @param bb
* @param index
* @return
*/
public static double getDouble(byte[] b, int index) {
long l;
l = b[0];
l &= 0xff;
l |= ((long) b[1] << 8);
l &= 0xffff;
l |= ((long) b[2] << 16);
l &= 0xffffff;
l |= ((long) b[3] << 24);
l &= 0xffffffffl;
l |= ((long) b[4] << 32);
l &= 0xffffffffffl;
l |= ((long) b[5] << 40);
l &= 0xffffffffffffl;
l |= ((long) b[6] << 48);
l &= 0xffffffffffffffl;
l |= ((long) b[7] << 56);
return Double.longBitsToDouble(l);
}
  1. boolean与byte的相互转化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 将boolean转成byte[]
* @param val
* @return byte[]
*/
public static byte[] Boolean2ByteArray(boolean val) {
int tmp = (val == false) ? 0 : 1;
return ByteBuffer.allocate(4).putInt(tmp).array();
}

/**
* 将byte[]转成boolean
* @param data
* @return boolean
*/
public static boolean ByteArray2Boolean(byte[] data) {
if (data == null || data.length < 4) {
return false;
}
int tmp = ByteBuffer.wrap(data, 0, 4).getInt();
return (tmp == 0) ? false : true;
}

参考地址:
[1].long、shrot和int转化 https://blog.csdn.net/u012403290/article/details/68943827
[2].long、shrot和int转化 https://blog.csdn.net/thanklife/article/details/17002641
[3]. char、float、double与byte转化 https://blog.csdn.net/LEEtcWorks/article/details/7390731
[4]. 通过buffer转换 https://blog.csdn.net/u010983881/article/details/60870360