因为转换会用到运算符和补码的知识,下面先对运算符的使用做个简单的介绍。
与(&)、非(~)、或(|)、异或(^)简介
1.与运算符
与运算符用符号“&”表示,其使用规律如下:
两个操作数中位都为1,结果才为1,否则结果为0,例如下面的程序段。
public static void main(String[] args) {
int a = 129;
int b = 128;
System.out.println("a 和b 与的结果是:" + (a & b));
}
运行结果
a 和b 与的结果是:128
下面分析这个程序:
“a”的值是129,转换成二进制就是10000001,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道结果就是10000000,即128。
2.或运算符
或运算符用符号“|”表示,其运算规律如下:
两个位只要有一个为1,那么结果就是1,否则就为0,下面看一个简单的例子。
public static void main(String[] args) {
int a = 129;
int b = 128;
System.out.println("a 和b 或的结果是:" + (a | b));
}
运行结果
a 和b 或的结果是:129
下面分析这个程序段:
a 的值是129,转换成二进制就是10000001,而b 的值是128,转换成二进制就是10000000,根据或运算符的运算规律,只有两个位有一个是1,结果才是1,可以知道结果就是10000001,即129。
3.非运算符
非运算符用符号“~”表示,其运算规律如下:
如果位为0,结果是1,如果位为1,结果是0,下面看一个简单例子。
public static void main(String[] args) {
int a = 2;
System.out.println("a 非的结果是:" + (~a));
}
运行结果
a 非的结果是:-3
4.异或运算符
异或运算符是用符号“^”表示的,其运算规律是:
两个操作数的位中,相同则结果为0,不同则结果为1。下面看一个简单的例子。
public static void main(String[] args) {
int a = 15;
int b = 2;
System.out.println("a 与 b 异或的结果是:" + (a ^ b));
}
运行结果
a 与 b 异或的结果是:13
分析上面的程序段:a 的值是15,转换成二进制为1111,而b 的值是2,转换成二进制为0010,根据异或的运算规律,可以得出其结果为1101 即13。
补码反码介绍
1.原码:
一个byte是一个字节,一个字节是由8个位组成。其中最高位是符号位,范围就是127 ~ -128。
即:0111 1111~1111 1111
也就是说:0000 0001 代表的是1,
1000 0000 代表的是-128。
反码
正数的反码是其本身(正数的符号位是0);
负数的反码是:在原码的基础上,符号位不变,其他位取反。(负数的符号位是1)
即:-128的原码是:1000 0000
反码是:1111 1111
补码
补码是在原码的基础上,符号位不变,其他位取反+1。
例如: 1的原码是:0000 0001
反码是:0000 0001
符号位不变,取反: 0111 1111
+1(逢二进一)
补码是:1111 1111
下面开始上正菜
以int和byte互转为例进行分析
public static void main(String[] args) {
int a = 129;
// 第一组 第二组 第三组 第四组
// 2的二进制表示完整为 "[00000000][00000000][00000000][00000010]"[]括号实际没有,为了看起来清楚加的
byte[] b = new byte[4];
// 向右移位是 低位舍弃,高位补符号位
// 向右移位运算,移动24位后,高8位,被移动到低8位上,二、三、四组都会被丢弃
b[0] = (byte) (a >> 24);
// 向右移动16位,高16位到低16位地方,第三、四组会被舍弃,至于&0xff这里不容易看出来,b[3]那一行能看出来
b[1] = (byte) ((a >> 16) & 0xff);
// 移动8位第四组会被丢弃,结果还是0
b[2] = (byte) ((a >> 8) & 0xff);
// 不移动直接进行与(&)运算,0xff的二进制是第四位为8个1 其他是0的数,作用就是排除不想要的位
// 这里来个例子 [00000000][00000100][00000100][00000010]假如有这么个二进制的数字
// 如果你想取到[00000100]字节的值 , 先对其向右移动8位变为
// [00000000][00000000][00000100][00000100]
// 然后和0xff与运算,0xff二进制[00000000][00000000][00000000][11111111]
// 与运算后的结果就为[00000000][00000000][00000000][00000100]
// 这样需要的字节就拿到了
b[3] = (byte) (a & 0xff);
for (byte c : b) {
System.out.print(Integer.toBinaryString(c & 0xff) + " ");
}
System.out.println();
// 把字节转回Int和上面颠倒下,就不多说了。
int i = 0;
i += ((b[0] & 0xff) << 24);
i += ((b[1] & 0xff) << 16);
i += ((b[2] & 0xff) << 8);
i += ((b[3] & 0xff));
System.out.println(i);
}
问题:为什么要&0xff?
首先0xff是十六进制的255,也就是二进制的1111 1111,对0xff取与,实际上就是要取这个数最低八位的值,截一个字节的长度。
如果不用&0xff:
①计算机中是用补码的方式进行存储数据。
②如果不用&0xff,那么在进行负数的运算时就会出现问题,如:使用-1进行运算,-1的byte补码是:1111 1111,对应的十六进制数字是0xff;
-1的int补码(32位)是1111 1111 1111 1111 1111 1111,如果将byte转换为int,那么对应的十六进制数是0xffff。
结果不正确(对于负数而言)。
所以为了计算结果的正确性,我们就要对字节进行&0xff操作。
算法实现
public class Utilities {
public static byte[] int2Bytes(int num) {
byte[] byteNum = new byte[4];
for (int ix = 0; ix < 4; ++ix) {
int offset = 32 - (ix + 1) * 8;
byteNum[ix] = (byte) ((num >> offset) & 0xff);
}
return byteNum;
}
public static int bytes2Int(byte[] byteNum) {
int num = 0;
for (int ix = 0; ix < 4; ++ix) {
num <<= 8;
num |= (byteNum[ix] & 0xff);
}
return num;
}
public static byte int2OneByte(int num) {
return (byte) (num & 0x000000ff);
}
public static int oneByte2Int(byte byteNum) {
return byteNum > 0 ? byteNum : (128 + (128 + byteNum));
}
public static byte[] long2Bytes(long num) {
byte[] byteNum = new byte[8];
for (int ix = 0; ix < 8; ++ix) {
int offset = 64 - (ix + 1) * 8;
byteNum[ix] = (byte) ((num >> offset) & 0xff);
}
return byteNum;
}
public static long bytes2Long(byte[] byteNum) {
long num = 0;
for (int ix = 0; ix < 8; ++ix) {
num <<= 8;
num |= (byteNum[ix] & 0xff);
}
return num;
}
public static void main(String[] args) {
int num = 129;
System.out.println("测试的int值为:" + num);
byte[] int2bytes = Utilities.int2Bytes(num);
System.out.printf("int转成bytes: ");
for (int i = 0; i < 4; ++i) {
System.out.print(int2bytes[i] + " ");
}
System.out.println();
int bytes2int = Utilities.bytes2Int(int2bytes);
System.out.println("bytes转行成int: " + bytes2int);
byte int2OneByte = Utilities.int2OneByte(num);
System.out.println("int转行成one byte: " + int2OneByte);
int oneByte2Int = Utilities.oneByte2Int(int2OneByte);
System.out.println("one byte转行成int: " + oneByte2Int);
System.out.println();
long longNum = 100000;
System.out.println("测试的long值为:" + longNum);
byte[] long2Bytes = Utilities.long2Bytes(longNum);
System.out.printf("long转行成bytes: ");
for (int ix = 0; ix < long2Bytes.length; ++ix) {
System.out.print(long2Bytes[ix] + " ");
}
System.out.println();
long bytes2Long = Utilities.bytes2Long(long2Bytes);
System.out.println("bytes转行成long: " + bytes2Long);
}
}