
1.二进制基础
二进制数分为有符号的二进制数和无符号的二进制数
1.1 无符号整数
无符号数是相对有符号数而言,指的是整个机器字长的全部二进制位均表示数值位,相对于数的绝对值。无符号的二进制只能表示非负整数
1.2 有符号整数
既可以表示正数,也可以表示负数,只是符号位不同,正数的符号位为0,负数的符号位为1
1.3 有符号整数和无符号整数的范围
一个无符号的整数有:2n个,其范围是:0~2n
一个有符号的整数有:2n,其中正数有2n-1,负数有2n-1,其范围是:-2n-1~2n-1-1
负数用二进制表示
-5 => 0101 => 0100 => 1011
1.先找到该负数对应的正数的二进制数
2.将该二进制数减1
3.然后再对得到的结果按位一一取反
得到的结果即为该负数对应的二进制数
判断一个二进制数是那个负数
1010 => 0101 => 0110 => -6
1.将该二进制数按位一一取反
2.将取反后的二进制数加1
3.得到对应的正数
则原二进制数对应的负数为该正数的相反数
特例:在该范围内的整数的最小值,他的相反数和绝对值都是自己
假设在 4 个bit位 的情况下-8 这个数字是不能表示为 8 的,
-8:1000 => 0111 => 1000还是8所以不能表示为 8
2.二进制打印函数
// 本文件的实现是用int来举例的
// 对于long类型完全同理
// 不过要注意,如果是long类型的数字num,有64位
// num & (1 << 48),这种写法不对
// 因为1是一个int类型,只有32位,所以(1 << 48)早就溢出了,所以无意义
// 应该写成 : num & (1L << 48)
// 打印一个int类型的数字,32位进制的状态
// 左侧是高位,右侧是低位
public static void printBinary(int num){
for (int i = 31; i >= 0; i--) {
// 下面这句写法,可以改成 :
// System.out.print((a & (1 << i)) != 0 ? "1" : "0");
// 但不可以改成 :
// System.out.print((a & (1 << i)) == 1 ? "1" : "0");
// 因为a如果第i位有1,那么(a & (1 << i))是2的i次方,而不一定是1
// 比如,a = 0010011
// a的第0位是1,第1位是1,第4位是1
// (a & (1<<4)) == 16(不是1),说明a的第4位是1状态
System.out.print((num & (1 << i)) == 0 ? "0" : "1");
}
System.out.println();
}
3.十六进制和二进制的直接形式定义
- 十六进制数:0x4e 可以将4 和 e 分别用四位二进制数进行表示,得到的结果写在一起即为0x4e的二进制形式
0100->4 1110->e 0x4e->01001110 - 二进制数可用0b加对应的数的二进制来表示
4.常见的位运算
或,与,异或 | & ^(具体运算法则在注释中展示)
int g = 0b0001010;
int h = 0b0001100;
printBinary(g | h);//当g,h上的对应位有一位为1的时候为1,其余是0
printBinary(g & h);//当g,h上的对应位都为1则为1,其余为0
printBinary(g ^ h);//g,h对应位上的数字相同则为0,不同则为1
System.out.println("===g、h===");
上述代码运行结果如下:
00000000000000000000000000001110
00000000000000000000000000001000
00000000000000000000000000000110
===g、h===
左移运算符<<
int i = 0b0011010;
printBinary(i);
printBinary(i << 1);
printBinary(i << 2);
printBinary(i << 3);
System.out.println("===i << ===");
运行结果如下:
00000000000000000000000000011010
00000000000000000000000000110100
00000000000000000000000001101000
00000000000000000000000011010000
左移运算符:原有状态向左移动,右边空出来的位置用0补全
同时,左移n位就相当于原数乘以2n
- 右移运算符 >> 和 >>>
非负数
两个右移运算符没有区别,运算法则都为将原来的数整体向右移动两位,左边空出的位置用0来补全 例如:
i: 00000000000000000000000000011010
i>>2: 00000000000000000000000000000110
i>>>2:00000000000000000000000000000110
负数
i:11110000000000000000000000000000
i>>2:11111100000000000000000000000000
i>>>2:00111100000000000000000000000000
对于负数来说 >> 当该数右移出相应的位数后,左边空出来的数用1来补全
对于>>> 当该数右移出相应的位数后,左边空出来的数一律用0来补全
同时,右移n位得到的结果相当于原数除以2n,只有非负数符合这个特征,负数不要用
左移右移结果如下:
int k = 10;
System.out.println(k);
System.out.println(k << 1);
System.out.println(k << 2);
System.out.println(k << 3);
System.out.println(k >> 1);
System.out.println(k >> 2);
System.out.println(k >> 3);
System.out.println("===k===");
运行结果如下:
10
20
40
80
5
2
1
===k===
5.逻辑运算符注意事项
可以这么写 : int num = 3231 | 6434;
可以这么写 : int num = 3231 & 6434;
不能这么写 : int num = 3231 || 6434;
不能这么写 : int num = 3231 && 6434;
因为 ||、&& 是 逻辑或、逻辑与,只能连接boolean类型
不仅如此,|、& 连接的两侧一定都会计算
而 ||、&& 有穿透性的特点
以下通过一段代码来具体解析二者的区别
System.out.println("test1测试开始");
boolean test1 = returnTrue() | returnFalse();
System.out.println("test1结果," + test1);
System.out.println("test2测试开始");
boolean test2 = returnTrue() || returnFalse();
System.out.println("test2结果," + test2);
System.out.println("test3测试开始");
boolean test3 = returnFalse() & returnTrue();
System.out.println("test3结果," + test3);
System.out.println("test4测试开始");
boolean test4 = returnFalse() && returnTrue();
System.out.println("test4结果," + test4);
System.out.println("===|、&、||、&&===");
public static boolean returnTrue() {
System.out.println("进入了returnTrue函数");
return true;
}
public static boolean returnFalse() {
System.out.println("进入了returnFalse函数");
return false;
}
运行结果如下:
- test1测试开始
进入了returnTrue函数
进入了returnFalse函数
test1结果,true
2.test2测试开始
进入了returnTrue函数
test2结果,true
3.test3测试开始
进入了returnFalse函数
进入了returnTrue函数
test3结果,false
4.test4测试开始
进入了returnFalse函数
test4结果,false
=|、&、||、&&=
由此可见,普通的 | 和 & 运算符左右两侧都会被计算,而逻辑或 || 和逻辑与 &&,因其具有穿透性的特点,不会被全部计算,只要找到符合条件的情况就会停止

935






