综述
操作符(Operators)在Java语言中用于操作数据和变量。
位运算符
按位运算符处理二进制数字或输入值的二进制数字,可以应用于整数类型 - long,int,short,char和byte。
按位运算符处理十进制数的二进制数据,并根据给定运算符按比特对它们执行操作。
- 首先,操作数转换为其二进制表示;
- 接下来,对每个二进制数应用运算符并计算结果;
- 最后,结果被转换回十进制表示
例子:
int value1 = 6;
int value2 = 5;
OR运算符
int result = 6 | 5;
将数字转化为二进制
Binary number of value1 = 0110
Binary number of value2 = 0101
OR操作会应用于每个bit,结果返回一个新的二进制数
0110
0101
-----
0111
最后,结果0111将被转换回等于7的十进制数。
result : 7
按位运算符又分为按位逻辑操作符和按位移位操作符。
按位逻辑运算符
按位逻辑运算符是AND(&)、OR(|)、XOR(^)和NOT(~)。
按位与(&)
AND运算符比较两个整数的每个二进制数字,如果两个数字都是1,则返回1,否则返回0。
@Test
public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber() {
int value1 = 6;
int value2 = 5;
int result = value1 & value2;
assertEquals(4, result);
}
0110
0101
-----
0100
按位或(|)
OR运算符比较两个整数的每个二进制数字,如果其中一个为1,则返回1。
按位XOR(^)
异或运算符比较两个整数的每个二进制数字,如果比较的两个位数都不相同,则返回1。如果两个整数的位都是1或0,结果将是0;否则,结果将是1。
@Test
public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber() {
int value1 = 6;
int value2 = 5;
int result = value1 ^ value2;
assertEquals(3, result);
}
0110
0101
-----
0011
按位补码(~)
按位Not或补码(cOMPLEMENT)操作符表示对输入值的每一位的取反。它只取一个整数,等价于!操作符。
@Test
public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() {
int value1 = 6;
int result = ~value1;
assertEquals(-7, result);
}
value1的二进制格式为:
value1 = 0000 0110
通过应用补码运算符,结果是
0000 0110 -> 1111 1001
这是十进制数 6 的补码,由于第一个(最左边的)位是二进制的 1,这意味着存储的数字的符号为负。现在,由于数字存储为 2 的补码,首先我们需要找到它的 2 的补码,然后将结果二进制数转换为十进制数:
1111 1001 -> 0000 0110 + 1 -> 0000 0111
最后,0000 0111 是十进制的 7。由于符号位如上所述为 1,因此得到的答案是:-7
按位运算符表
A B A|B A&B A^B ~A
0 0 0 0 0 1
1 0 1 0 1 0
0 1 1 0 1 1
1 1 1 1 0 0
按位移位运算符
二进制移位运算符将输入值的所有位基于移位运算符向左或向右移动,其操作语法为:
value <operator> <number_of_times>
表达式的左边是被移位的整数,表达式的右边表示其被移位的次数。按位移位运算符进一步分为按位左移和按位右移运算符。
有符号左移 [<<]
左移运算符将bits向左移动指定的次数,左移后,右边的空格被0填充。另一个需要注意的重要一点是,将一个数字移一个相当于将它乘以 2,或者,一般来说,将一个数字左移 n 个位置相当于乘以 2^n。
例子:将12左移2位,12的二进制是00001100,左移2位后的结果是00110000,相当于十进制的48。
@Test
public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
int value = 12;
int leftShift = value << 2;
assertEquals(48, leftShift);
}
对于负数也是类似的:
@Test
public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
int value = -12;
int leftShift = value << 2;
assertEquals(-48, leftShift);
}
有符号右移 [>>]
右移运算符将所有位右移,根据输入的数字填充左侧的空白区域:
- 当输入数字为负数时,最左边的位为 1,则空格将填充为 1;
- 当输入数字为正数时,最左边的位为 0,则空格将填充为 0
例子:对12右移2位,输入的数字是正数,所以右移2位后的结果是0011,也就是十进制的3:
@Test
public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
int value = 12;
int rightShift = value >> 2;
assertEquals(3, rightShift);
}
对负数来说:
@Test
public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
int value = -12;
int rightShift = value >> 2;
assertEquals(-3, rightShift);
}
无符号右移 [>>>]
此运算符与带符号的右移运算符非常相似。唯一的区别是左边的空格用0填充,而不管数字是正数还是负数。因此,结果将始终为正整数。
@Test
public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
int value = 12;
int unsignedRightShift = value >>> 2;
assertEquals(3, unsignedRightShift);
@Test
public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
int value = -12;
int unsignedRightShift = value >>> 2;
assertEquals(1073741821, unsignedRightShift);
}
按位运算符和逻辑运算符之间的区别
- 首先,逻辑运算符处理布尔表达式并返回布尔值(真或假),而按位运算符处理整数值的二进制数字(long、int、short、char 和 byte)并返回整数;
- 此外,逻辑运算符始终计算第一个布尔表达式,并且根据其结果和使用的运算符,可能会也可能不会计算第二个。另一方面,按位运算符总是计算两个操作数;
- 最后,逻辑运算符用于根据多个条件进行决策,而按位运算符则处理位并执行逐位运算。
用例
按位运算符的一些潜在用例是:
- 通信堆栈,其中附加到数据的标头中的各个位表示重要信息;
- 在嵌入式系统中,只设置/清除/切换特定寄存器的一位,而不修改其余位;
- 使用 XOR 运算符加密数据以解决安全问题;
- 通过将数据从一种表示形式转换为另一种表示形式进行数据压缩,以减少使用的空间量