- Java 中的逻辑运算符
- 逻辑否定运算符!
- 逻辑 AND - &,以及条件 AND - &&
- 逻辑或是运算符|,条件或是运算符||
- XOR - 逻辑异或 - 运算符 ^
- 逻辑运算的优先级
- 复杂的逻辑表达式
- 按位(bitwise)运算符
- 位运算符 &, | 和^
- 附加代码
- 按位求反运算符 ~
Java中的逻辑运算
逻辑运算是使用布尔运算符执行的。请原谅我的同义反复,但事情确实就是这样。基本逻辑运算(在编程和数学中)可以应用于逻辑参数(操作数),也可以用于形成更复杂的表达式,类似于数字的算术运算。例如表达式:
(a | b) | (c < 100) & !(true) ^ (q == 5)
是一个具有四个操作数的复杂逻辑表达式: (a | b)
,其中а
和b
是类型变量boolean
(c < 100)
(true)
(q == 5)
。反过来,简单逻辑表达式(a | b)
也由两个操作数参数组成。 逻辑操作数是一个可以说是 true 或 false、true或false的表达式。在 Java 术语中,布尔操作数是类型或布尔值的表达式boolean
,例如:
(2 < 1)
— 逻辑操作数,其值为falsetrue
- 其值显然为true 的逻辑操作数boolean a
- 也可以是逻辑操作数,如布尔值 aint a = 2
-不是逻辑操作数,它只是类型变量int
String a = "true"
也不是逻辑操作数。这是一个文本值为 的字符串"true"
。
- 逻辑否定,也称为
NOT
反转。在Java中,是用!
操作数前的“ ”符号来表示的。适用于一个操作数。 - 逻辑 and,它也是
AND
一个连词。&
由应用它的两个操作数之间的“ ”符号指示。 - 逻辑或者在Java中,它也是-
OR
,它也是析取。在Java中,用两个操作数之间的符号“|
”来表示。 - 异或,
XOR
, 严格析取。在Java中,用两个操作数之间的符号“^
”来表示。 - 在 Java 中,逻辑运算符包括条件 or,表示为
||
,以及条件 and -&&
。
==
不被视为逻辑运算符。 注意力!在 Java 中,逻辑运算符&
,|
和^
也适用于整数。在这种情况下,它们的工作方式略有不同,称为按位逻辑运算符。关于他们 - 在文章的末尾。让我们看一下表格,其中简要描述了每个 Java 逻辑运算符,下面我们将更详细地描述它们并提供代码示例。
Java运算符 | 姓名 | 类型 | 简短的介绍 | 例子 |
---|---|---|---|---|
! |
逻辑“非”(否定) | 一元 | !x 意思是“不是x”。如果操作数为false,则返回true。如果操作数为true则返回false。 |
boolean x = true; 然后 // !x == false |
& |
逻辑与(AND ,乘法) |
二进制 | 如果两个操作数都为true则返回true。 | a = true; b = false; 然后 a & b == false |
| |
逻辑或(OR ,加法) |
二进制 | 如果至少有一个操作数为true ,则返回true。 | a = true; b = false; 然后 a | b == true |
^ |
逻辑异或 ( XOR ) |
二进制 | 如果一个且只有一个操作数为true ,则返回true。如果两个操作数均为true或false则返回false。本质上,如果操作数不同,则返回true 。 | a = true; b = false; 然后 a ^ b == true |
&& |
条件 AND(短逻辑 AND) | 二进制 | 与 相同,& 但如果 左侧的操作数& 为false,则该运算符返回false而不检查第二个操作数。 |
|
|| |
条件 OR(短逻辑 OR) | 二进制 | 与 相同,| 但如果左侧的运算符为true,则该运算符返回true而不检查第二个操作数。 |
逻辑否定运算符!
该运算符是一元运算符,这意味着它适用于单个布尔表达式或操作数。它很容易理解,就像任何否定一样:运算符只是将表达式的含义更改为相反的含义。真值表或执行否定运算的结果:的值 | !A |
错误的 | 真的 |
真的 | 错误的 |
public class Solution {
public static void main(String[] args) {
boolean a = true;
System.out.println(!a); // here our boolean expression reverses its value
System.out.println(!false); // non-false expression, as you might guess, will be equal to... what?
System.out.println(!(2 < 5)); // expression (2 < 5) is true, so its negation is false
}
}
程序的输出如下:
false
true
false
逻辑 AND - &,以及条件 AND - &&
逻辑 AND 或合取应用于两个表达式,只有当两个操作数都为 true 时,其结果才为 true。也就是说,如果a
or操作数之一b
为false ,则无论第二个运算符的值如何,表达式都a & b
将为false 。如果您想象true是数字 1,false是 0,那么该运算符的工作&
方式与常规乘法完全相同。因此,逻辑与通常被称为“逻辑乘法”。顺便说一句,这个事实有助于快速记住运算符的操作&
,而不是将其与逻辑或运算符混淆|
。真值表AND,也是运算符工作的结果&
A | 乙 | a&b |
真的 | 真的 | 真的 |
真的 | 错误的 | 错误的 |
错误的 | 真的 | 错误的 |
错误的 | 错误的 | 错误的 |
public class Solution {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = true;
System.out.println(a & b); // if we multiply true by false, we will definitely get false
System.out.println(a & c); // true to true will be true
System.out.println(false & (2 > 5));
System.out.println((2 < 5) & false);
// regardless of the truthfulness of the expression in brackets, in which case we have to be content with false
}
}
程序结果:
false
true
false
false
该运算符&&
有时称为“短 AND”。当使用逻辑操作数时,它会产生与运算符相同的结果&
。然而,他的作品本身却存在着差异。因此,您已经注意到,如果a & b
表达式 () 中的操作数a
为false,则检查操作数的值就没有意义b
:运算结果肯定为false。因此,如果我们根本不需要第二个操作数的值,那么使用它&&
可以减少程序中的计算次数。如果我们将示例中的所有运算符替换&
为&&
,结果将完全相同,但程序本身会运行得更快一些(尽管我们不会注意到这一点,因为我们正在谈论 mili-micro...简而言之,非常小的时间单位)。
逻辑或是运算符|,条件或是运算符||
Java 中的 OR 运算符用符号 表示|
。逻辑或或析取应用于两个表达式,当且仅当两个操作数都为假时,其结果将为假。在这里,我们在某种程度上观察到与运算符 的情况相同的情况&
,但恰恰相反。也就是说,如果至少一个操作数为true ,则无论第二个运算符的值如何,表达式a | b
都保证为true 。如果&
它的行为类似于逻辑乘法,那么 OR 就是逻辑加法,如果您想象true为 1,false为 0。请记住,逻辑加法的工作方式与普通加法不同。在这种情况下,1 + 1 不等于 2,而是等于 1(数字 2 在该系统中根本不存在)。有时析取被理解为 0 和 1 中的最大值,在这种情况下,如果至少一个操作数等于 1 ( true ),我们就得到完全true。OR 真值表,也称为运算符的结果|
:
A | 乙 | 一个 | 乙 |
真的 | 真的 | 真的 |
真的 | 错误的 | 真的 |
错误的 | 真的 | 真的 |
错误的 | 错误的 | 错误的 |
public class Solution {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = true;
System.out.println(!a | b); // Compose the use of two logical operators: a == true, so !a, as we already know, is false.
System.out.println(a | c);
System.out.println((2 < 5) | false); // expression (2 < 5) is true, which means that for any second operand we get a true result
System.out.println((2 > 5) | true);
}
}
结果:
false
true
true
true
如果我们使用条件 OR 运算符 -||
而不是|
,我们将得到完全相同的结果,但是,与条件 AND 的情况一样&&
,它会经济地运行:如果我们“遇到”第一个操作数等于true,则不检查第二个操作数,但结果立即为true。
XOR Java - 逻辑异或 - 运算符 ^
XOR
、模2加法、逻辑异或、逻辑减法、严格析取、按位补……运算符^
在布尔代数中有很多名字。如果操作数不同,则将此运算符应用于两个操作数,结果将为true ;如果操作数相同,则结果为false 。因此,用减去零( false)和减去一(true )来比较它是很方便的。真值表XOR
,也称为运算符的结果^
:
布尔值 | 布尔值b | ^b |
真的 | 真的 | 错误的 |
真的 | 错误的 | 真的 |
错误的 | 真的 | 真的 |
错误的 | 错误的 | 错误的 |
public class Solution {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = true;
System.out.println(!a ^ b); // Compose the use of two logical operators: a == true, so !a, as we already know, is false.
System.out.println(a ^ c);
System.out.println((2 < 5) ^ false);
System.out.println((2 > 5) ^ true);
}
}
结果:
false
false
true
true
逻辑运算的优先级
就像在数学中一样,在编程中,当运算符出现在同一表达式中时,它们具有特定的执行顺序。一元运算符比二元运算符有优势,乘法(甚至逻辑)比加法有优势。我们将逻辑运算符排列在列表中越高,它们的优先级就越高:!
&
^
|
&&
||
&
and |
) 具有不同的优先级:
public class Solution {
public static void main(String[] args) {
boolean a = true, b = true, c = false;
System.out.println(a | b & c);
}
如果我们从左到右进行操作,即先应用运算符|
,然后应用 - &
,我们将得到值false。但事实上,如果您运行该程序,您将确定输出将为true,因为逻辑 AND 运算符&
将比逻辑 OR 运算符具有更高的优先级|
。为了避免混淆,您需要记住什么&
行为类似于乘法,|
什么行为类似于加法。您可以更改优先顺序。只需使用括号,就像学校数学一样。让我们稍微改变一下示例代码:
public class Solution {
public static void main(String[] args) {
boolean a = true, b = true, c = false;
System.out.println((a|b)&c);
}
这是怎么回事?首先我们在括号中使用逻辑加法,然后使用乘法。结果将是错误的。
复杂的逻辑表达式
当然,我们可以将布尔表达式和运算符结合起来。让我们记住文章开头的那句话:(a | b) | (c < 100) & !(true) ^ (q == 5)
现在看起来没那么可怕了。a
让我们编写一个程序来显示其值,之前已经确定了、b
和с
的值q
。计算复杂布尔表达式的值的示例
public class Solution {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
int c = 25;
int q = 2;
System.out.println((a|b) | (c < 100) & !(true)^(q == 5));
}
}
笔记:q
我们的变量是类型int
,但这q == 5
是一个布尔表达式,并且它等于false,因为上面我们用q
数字 2 进行了初始化。变量 也是如此c
。该数字等于 25,但 (c < 100) 是一个等于true的布尔表达式。该程序的结果:
true
复杂的布尔表达式可用于测试非常复杂和分支条件,但不应过度使用它们:它们会使代码难以阅读。
按位(bitwise)运算符
在文章开头,我们提到运算符&
,|
和^
可以与 Java 整数类型相关。在这种情况下,它们是按位运算符。它们也称为按位,因为一位数就是一位,并且这些运算专门针对位进行。当然,它们的工作方式与逻辑运算符有些不同,要准确理解它们的工作方式,您需要知道什么是二进制数字系统。如果你对此一无所知或者完全忘记了,我们建议你先阅读《Java:位和字节》一文,并提醒大家,在二进制数系统中只有两位数——0和1,所有数据在计算机中使用条件零和一来精确表示。我们习惯的任何数字(十进制;对于它们来说,有从 0 到 9 的 10 个不同的数字,我们可以用它们来书写任何数字)可以用二进制数字系统来表示。您可以使用数字系统基数 (2) 按顺序除法将十进制数转换为二进制数。每一步除法的余数以相反的顺序写出,将为我们提供所需的二进制数。例如,这里是将十进制数 103 转换为二进制表示形式:
JavaRush 课程中的二进制数字系统 在 JavaRush 课程中,他们在学习多线程任务(第 10 级,讲座 1)时谈论二进制数字系统;讲座结束后有几个需要巩固的任务。然而,这个主题一点也不困难,即使您在课程中还没有学到那么深,您也可能会弄清楚。 |
&
,Java 还使用按位运算符: |
^
~
按位求反运算符>>
按位右移>>>
无符号按位右移<<
按位左移
位运算符 &, | 和^
让我们看一下这些运算符如何工作的示例。假设我们有两个整数:int a = 25;
int b = 112;
我们需要对它们进行三个操作&
,|
并将^
结果显示在屏幕上。这是程序代码:
public class Solution {
public static void main(String[] args) {
int a = 25;
int b = 112;
int res1 = a & b;
int res2 = a | b;
int res3 = a ^ b;
System.out.println("a & b = " + res1);
System.out.println("a | b = " + res2);
System.out.println("a ^ b = " + res3);
}
}
程序运行结果如下:
a & b = 16
a | b = 121
a ^ b = 105
如果你不明白发生了什么,结果就会看起来非常非常神秘。事实上,一切都比看起来简单。位运算符“看到”二进制形式的操作数。然后他们将逻辑运算符或&
应用于两个数字的相应数字(位)。因此,对于数字 25 的二进制表示形式的最后一位,逻辑上与数字 112 的二进制表示形式的最后一位相加,即倒数第二位与倒数第二位,依此类推: 相同的逻辑可以在和的情况。 |
^
&
|
^
向左或向右位移位
Java 中有多种移位运算符。最常用的运算符<<
是 和>>
。它们分别将数字的二进制表示向左或向右移动,在向右移动的情况下,同时保留符号(我们将在下面解释保留符号的含义)。还有另一个右移运算符>>>
。它做同样的事情,但>>
不保存标志。那么,让我们用一个例子来看看他们的工作。 int a = 13
a << 1
将数字 a 的二进制表示形式的所有位向左移动 1 位。为了简单起见,我们将数字 13 想象成二进制的 0000 1101。事实上,这个数字看起来像这样:00000000 00000000 00000000 00001101,因为 Javaint
为数字分配了 4 个字节或 32 位。然而,这在示例中不起作用,因此在本示例中我们将认为我们的数字是一字节。 右侧空出的位用零填充。此操作的结果是,我们得到数字 26。 a << 2
它将数字的二进制表示形式的所有位a
向左移动 2 位,右侧空出的两位用零填充。结果,我们将得到数字 52。 a << 3
结果将是 104...注意到这个模式了吗?按位a
左移 n 个位置就像将数字a
乘以 2 的 n 次方。这同样适用于负数。这-13 << 3
将给出结果-104。 a >> n
将数字的二进制表示向右移动 n 位。例如,13 >> 1
将数字 1101 转换为数字 0110,即 6。13 >> 2
结果将是 3。也就是说,本质上,这里我们将数字除以 2 的 n 次方,其中 n 是移位次数向右,但有一个警告:如果数字是奇数,在此操作期间我们似乎重置了数字的最后一位。但对于消极的情况则有所不同。比方说,如果您要求程序执行一项操作,请尝试检查程序将产生什么结果-13 >> 1
。您将看到数字 -7,而不是您想象的 -6。发生这种情况是由于 Java 和其他编程语言中负数的存储方式所致。它们存储在所谓的互补代码中。在这种情况下,最高有效数字(左边的数字)在符号下方给出。如果是负数,则最高位为 1。
附加代码
我们来考虑一下这个数字int a = 13
。如果在程序中使用命令将其二进制表示打印到控制台System.out.println(Integer.toBinaryString(a));
,那么我们将得到 1101。事实上,这是一种速记符号,因为类型编号int
在内存中占用 4 个字节,因此计算机“看到”的更多像这样:
00000000 00000000 00000000 00001101
最高有效数字为零,这意味着我们有一个正数。要转换为附加代码:
-
我们把数字-13写成所谓的“直接代码”。为此,请将数字的最高有效位更改为 1。
操作结果:10000000 0000000 0000000 00001101
-
接下来,我们反转除符号位之外的所有位(将 0 更改为 1,将 1 更改为 0)。事实上,我们已经改变了。
行动结果:11111111 11111111 11111111 11110010
(是的,步骤 1 和步骤 2 可以合并,但最好这样想)
- 将所得数字加 1。
操作结果:11111111 11111111 11111111 11110011
-13 >> 1
。由于我们的运算符>>
保留了符号,因此在此操作中,左侧释放的所有位都不是用零填充,而是用 1 填充。因此,移动数字
11111111 11111111 11111111 11110011
向右移动一位,产生以下位序列:
11111111 11111111 11111111 11111001
如果我们将这个数字转换为直接代码(即先减 1,然后反转除第一个之外的所有位),我们会得到这个数字:
10000000 00000000 00000000 00000111
或-7。现在我们已经了解了符号保留右移运算符,它与运算符 的区别就会变得清楚>>>
。 a >>> n
— 此操作是无符号移位,也就是说,它将数字的二进制表示形式a
向右移动 n 位,但不会像运算符 那样用 1 填充左侧空出的 n 位>>
,而是用 0 填充。我们来做手术吧-13 >>> 1
。-13
我们已经有了二进制补码的 数字:
11111111 11111111 11111111 11110011
通过右移 1 位并用零填充空闲位,我们得到以下数字:
01111111 11111111 11111111 11111001
什么给出了十进制数2147483641
。
按位求反运算符 ~
这个一元运算符的工作原理非常简单:它反转整数的二进制表示的每一位。让我们看一下数字-13
:
11111111 11111111 11111111 11110011
按位求反运算~13
将简单地反转每个位的值。结果我们得到:
00000000 00000000 00000000 00001100
或12
十进制形式。
简要结论
- 所有逻辑运算符都适用于布尔表达式,即那些可以说是true或false 的表达式。
- 如果运算符
&
,|
或^
应用于数字,我们就不再讨论逻辑运算,而是讨论按位运算。即,将两个数字都转换为二进制系统,并对这些数字逐位进行逻辑加法、乘法或减法运算。 - 在数理逻辑中,运算符
&
和|
对应于合取和析取。 - 逻辑 AND 类似于将 1 ( true ) 和 0 ( false ) 相乘。
- 逻辑或类似于查找 1 ( true ) 和 0 ( false ) 中的最大值。
- 对于整数 a 的按位求反,使用运算符
~a
。 - 要对布尔表达式 a 进行逻辑求反,请使用运算符
!a
。 - 负数以二进制补码形式存储和处理。
- 按位右移可能会
>>
也可能不会保留符号 (>>>
)。
GO TO FULL VERSION