🌟 想系统化学习 Java 编程?看看这个:[编程基础] Java · 学习手册
✅ 提示:本章只是作为一个了解技能点,如果小伙伴没看懂,可以跳过此技能点。
0x01:位运算符 — 概览
位运算符主要针对的是二进制数,对二进制数的所有位数依次从低位到高位进行运算。 在进行位运算时,会涉及补码到原码的转换(只有转换成原码后才能转换为十进制数)。二进制正数的补码与原码形式相同,负数的补码要想转化为原码,需要对补码进行取反后加一的操作。
本章我们涉及的运算符如下表多是,读者可以按需学习,如果都理解,可以快速跳过:
类别 | 符号 | 说明 |
---|---|---|
位运算符 | & | 按位与 |
位运算符 | | | 按位或 |
位运算符 | ~ | 按位取反 |
位运算符 | ^ | 按位异或 |
位运算符 | << | 按位左移,左移 1 位相当于乘 2 |
位运算符 | >> | 按位右移,右移 1 位相当于除 2 取商 |
位运算符 | >>> | 按位无符号右移 |
从上方的表格可以看出,位运算符的 &、|、^
与我们前面在逻辑运算符中讲的逻辑与、逻辑或、逻辑异或长得一摸一样,那么问题来了,我们实战中如何区分,哪个是位运算符?哪个是逻辑运算符呢?实战中,我们一般是通过运算符左右连接的数据类型来判断运算符的作用的:
-
逻辑运算符: 左右连接的是布尔类型的操作数。
-
位运算符: 左右连接的是具体的数值。
0x02:位运算符 — 详解
由于位运算符操作的是二进制数,所以下面的分析需要读者掌握十进制与二进制之间的转换。并且,由于计算机存储数据采用的是内存,所以读者还需要知道每种数据类型在内存中的存储格式,以及原码、补码与反码的相关概念。
笔者这里为了方便读者理解,将采用 byte 类型(在内存中占 1 个字节,即 8 位)进行演示。
0x0201:位运算符 &
详解
&
的运算法则位:两个二进制操作数只有对应的位都为 1 时,结果位才为 1,否则为 0。两个二进制数的按位与运算示例如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = 0b01001000;
System.out.println(num1 & num2);
}
}
0x0202:位运算符 |
详解
|
运算的法则为:两个二进制操作数只有对应的位都为 0 时,结果位才为 0,否则为 1。两个二进制数的按位或运算示例如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = 0b01001000;
System.out.println(num1 | num2);
}
}
0x0203:位运算符 ~
详解
~
的运算法则为:将操作数中的二进制数 1 变为 0,0 变为 1。二进制数的按位取反运算示例如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
System.out.println(~num1);
}
}
0x0204:位运算符 ^
详解
^
的运算法则为:若两个二进制操作数对应的位相同(同为 0 或同为 1)时,结果位为 0,否则为 1。两个二进制数按位异或运算示例如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = 0b01001000;
System.out.println(num1 ^ num2);
}
}
0x0205:位运算符 <<
详解
<<
的运算符法则为:将一个二进制数向左移动指定的位数。左边(高位)溢出的位数会被丢弃,右边(低位)空出的位置用 0 填补。按位左移相当于乘以 2 的 n 次幂。二进制数的按位左移运算示例如下(负数的补码到十进制数的转换有点特殊):
上面我们给的案例比较特殊,涉及到了计算机基础的源码、反码与补码的运算。如果读者不清楚,可以尝试问 AI “byte 型数据 01000001 左移一位,推导流程是咋样的,我要十进制结果”,AI 会很乐意告诉你推导流程的。这里我们直接上代码验证:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = (byte) (num1 << 1);
System.out.println(num2);
byte num3 = (byte) (num1 << 2);
System.out.println(num3);
}
}
0x0206:位运算符 >>
详解
>>
的运算法则为:将一个二进制操作数向右移动指定的位数。右边(低位)溢出的位数会被丢弃,对于左边(高位)空出的位置。如果最高位是 0(正数),则左侧填充 0,如果最高位是 1(负数),则左侧填充 1。按位右移相当于除以 2 的 n 次幂。二进制数的按位右移运算示例如下:
上面这个案例就比较简单了,没有涉及负数的补码与原码转换。对应的程序如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = (byte) (num1 >> 1);
System.out.println(num2);
byte num3 = (byte) (num1 >> 2);
System.out.println(num3);
}
}
0x0207:位运算符 >>>
详解
>>>
的运算法则为:将一个二进制操作数向右移动指定的位数。右边(低位)溢出的位数会被丢弃,对于左边(高位)空出的位置,直接补 0(简而言之,就是符号位也参与运算)。二进制数按位无符号右移运算示例如下:
public class TestVar {
public static void main(String[] args) {
byte num1 = 0b01000001;
byte num2 = (byte) (num1 >>> 1);
System.out.println(num2);
byte num3 = (byte) (num1 >>> 2);
System.out.println(num3);
}
}