一、计算机中存储的都是补码
java也是如此:
System.out.println(Integer.toBinaryString(2));
System.out.println(Integer.toBinaryString(-2));
运行结果:
10
11111111111111111111111111111110
由于整数默认int型,32位。正数的补码和原码都一样,高位的0默认不打印。因此是10。
-2
原码:1000 0000 0000 0000 0000 0000 0000 0010
反码:1111 1111 1111 1111 1111 1111 1111 1101 (在源码基础上符号位不变,其余位取反)
补码:1111 1111 1111 1111 1111 1111 1111 1110 (反码+1)
从上面的结论来看,java二进制数据是以补码来存储的。
二、运算也是在反码的基础上进行运算的
1. ~ 按位非(NOT)操作。每位取反。即原来是0的变成1,原来是1的变成0。
System.out.println(~ (-2)); //结果为1
分析:
step1 -> -2原码:1000 0000 0000 0000 0000 0000 0000 0010step2-> -2反码:1111 1111 1111 1111 1111 1111 1111 1101step3-> -2补码:1111 1111 1111 1111 1111 1111 1111 1110step4-> 对-2的补码进行取反即可得到~(-2)的补码
step5-> ~(-2)补码:0000 0000 0000 0000 0000 0000 0000 0001step6-> 由于符号位为0表示正数,因此补码和源码一样。转换为十进制就是1
2. & 按位与(AND)操作。1和1为1,1和0为0,0和0为0。
System.out.println(-3 & 2); //结果为0
分析:
step1 -> -3的原码:1000 0000 0000 0000 0000 0000 0000 0011step2-> -3的反码:1111 1111 1111 1111 1111 1111 1111 1100step3-> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step4-> 2的补码:0000 0000 0000 0000 0000 0000 0000 0010step5->step3和step4进行与运算即可得-3&2的补码,结果是正数,补码和原码相同。
step6-> -3&2补码: 0000 0000 0000 0000 0000 0000 0000 0000step7-> 转换为十进制就为0
3. | 按位或(OR)操作。1和1为1,1和0为1,0和0为0。
System.out.println(-3 | 2); //结果为-1
分析:
step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step2-> 2的补码:0000 0000 0000 0000 0000 0000 0000 0010step3->step1和step2进行或运算即可得到-3|2的补码
step4-> -3|2补码: 1111 1111 1111 1111 1111 1111 1111 1111step5->由于结果是在补码的基础上运算得来个,最高位为1表示负数,负数的补码和原码不相同,因此需要将补码转换为原码。
step6-> -3|2反码: 1111 1111 1111 1111 1111 1111 1111 1110(反码到补码是反码+1,因此补码到反码是补码-1)
step7-> -3|2原码: 1000 0000 0000 0000 0000 0000 0000 0001(符号位不变,反码取反)
step7-> 将step7的二进制转换为十进制,即为-1
4. ^ 按位异或(XOR)操作。不同为1,相同为0。1和1为0,1和0为1,0和0为0。
System.out.println(-3 ^ 2); //结果为-1
分析:
step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step2-> 2的补码:0000 0000 0000 0000 0000 0000 0000 0010step3->step1和step2做异或运算得到补码
step4-> -3^2补码: 1111 1111 1111 1111 1111 1111 1111 1111step5->由于结果是负数,因此需要将运算得补码转换为原码。
step6-> -3^2反码: 1111 1111 1111 1111 1111 1111 1111 1110(补码-1)
step7-> -3^2原码: 1000 0000 0000 0000 0000 0000 0001 0001(符号位不变,反码取反)
step8-> 将step7的二进制原码转换为十进制数,结果为-1
5. >> 右移位操作(var >> bit)。指定值所有位向右移动指定位数。低位舍弃,高位按符号位填充。没有溢出的情况下,相当于除以2的n次方。
System.out.println(-3 >> 3); //结果为-1
分析:
step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step2->右移3位
step3-> 右移后补码:1111 1111 1111 1111 1111 1111 1111 1111step4->高位为负数因此,高位补1,低位舍弃。负数要转换为原码
step5-> 右移后反码:1111 1111 1111 1111 1111 1111 1111 1110(补码-1)
step6-> 右移后原码:1000 0000 0000 0000 0000 0000 0000 0001(符号位不变,反码取反)
step7-> step6转换为十进制值为-1
6. >>> 无符号右移位操作(var >>> bit)。指定值所有位向右移动指定位数。低位舍弃,高位补0。
System.out.println(-3 >>> 3); //结果为536870911
分析:
step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step2->无符号右移3位,高位补0,低位舍弃。
step3-> 右移后补码:0001 1111 1111 1111 1111 1111 1111 1111step4-> 正数的补码和原码一样。结果为536870911
7. << 左移位操作(var << bit)。指定值所有位向左移动指定位数。低位补0,高位保留符号位。没有溢出的情况下,相当于乘以2的n次方。
System.out.println(-3 << 3); //结果为-24
分析:
step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101step2->左移3位,高位不变。低位补0
step3-> 右移后补码:1111 1111 1111 1111 1111 1111 1110 1000step4-> 右移后反码:1111 1111 1111 1111 1111 1111 1110 0111step5-> 右移后原码:1000 0000 0000 0000 0000 0000 0001 1000step6-> 将step5转换为十进制即为-24