二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。
原码、反码和补码
原码:一个整数,按照绝对值大小转换成的二进制数,最高位为符号位,称为原码。例如: 00000000 00000000 00000000 00000101 是 5的 原码;10000000 00000000 00000000 00000101 是-5的原码。
反码:将二进制数除符号位外按位取反,得到的新二进制数称为原二进制数的反码。正数的反码为原码,负数的反码除符号位外按位取反。例如:十进制5的二进制原码为00000000 00000000 00000000 00000101,其反码与原码相同;十进制-5的二进制原码为10000000 00000000 00000000 00000101,其反码为11111111 11111111 11111111 11111010。
补码:正数的补码为原码,负数的补码为反码+1。例如:十进制-5的二进制原码为10000000 00000000 00000000 00000101,反码为11111111 11111111 11111111 11111010,补码为11111111 11111111 11111111 11111011。
直接用原码计算有时会出现计算错误,例如:
1 - 1 = 0
00000001 + 10000001= 10000010 = -2
用反码可以解决以上问题:
1 - 1 = 0
00000001+ 11111110 = 11111111 = -0
但出现了正负零问题,补码出现的原因就是为了解决正负零问题,例
1 - 1 = 0
00000001 + 11111111 = 00000000 = 0
因此,计算机中的计算都是用的补码。
有符号数和无符号数
二进制中存在有符号数和无符号数两种。有符号数中,二进制的最高位为符号位,0为正数,1为负数,例如:0111 1111的值为127,-1000 0000的值为-128,1byte即1个字节(8bit),因此1byte的取值为-128 ~ 127。而无符号数中,所有的位数都用来表示该数值,因此8位无符号数能表示的范围为0~255。
负数二进制转换十进制
- 对二进制按位取反;
- 对取反后的二进制+1;
- 转换成十进制,并在前面加-号。
位运算
- &与运算:两个数二进制对应的位都为1,该位的结果为1,否则为0。例如3&10即0000 0011 & 0000 1010 = 0000 0010 = 2;
- |或运算:两个数二进制对应的位任一个为1,该位的结果为1,否则为0。例如3|10即0000 0011 | 0000 1010 = 0000 1011 = 11;
- ~取反运算:单目运算符,将二进制中为1的变为0,为0的变为1。例如~3 = ~(0000 0011) = 1111 1100 = -4;
- ^异或运算:两个数二进制对应的位相同则为0,不同则为1。例如3^10即0000 0011 ^ 0000 1010 = 0000 1001 = 9;
- >>右移运算:运算符左边的数的二进制右移运算右边的数的大小个位数。例如a>>b表示a的二进制右移b个位数,其中当a是正数时,高位补0,a是负数时,高位补1;
- a << b:a的二进制表示左移b位,低位补0。因符号位会被移出去,可能会出现正数左移变负数,负数变正数。且当左移的位数超过该数据类型的最大位数时,编译器会用左移位数模该数据类型的最大位数,然后用余数作为左移的位数;
- a >>> b:a无符号右移b位,高位补0。
相关API
Integer包装类有将十进制int转换为二进制、八进制以及十六进制的方法。
//转换为32位的二进制,对于负数返回的是其补码
public static String toBinaryString(int i);
//转换为八进制
public static String toOctalString(int i);
//转换为十六进制
public static String toHexString(int i);
同样有将其他进制转换为十进制的方法,其实就是我们熟知的parseInt()和valueOf()方法,但是它们的重载方法,多了一个“进制”参数。
//将其他进制转换为十进制,返回Integer对象
public static Integer valueOf(String s, int radix) throws NumberFormatException;
//将其他进制转换为十进制,返回int
public static int parseInt(String s, int radix) throws NumberFormatException;
测试程序
public static void main(String[] args) {
System.out.println("***二进制***");
System.out.println(Integer.toBinaryString(-5));
System.out.println(Integer.valueOf("-101",2));
System.out.println(Integer.parseInt("-101",2));
System.out.println("***十六进制***");
System.out.println(Integer.toHexString(65535));
System.out.println(Integer.valueOf("FFFF",16));
System.out.println(Integer.parseInt("FFFF",16));
}
输出结果
***二进制***
11111111111111111111111111111011
-5
-5
***十六进制***
ffff
65535
65535