- 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,因為 Java為數字分配了int
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 的表達式。
- Если операторы
&
,|
or^
применяются к числам, речь идёт уже не о логических операциях, а о побитовых. То есть оба числа переводятся в двоичную систему и к этим числам побитово применяют операции логического сложения, умножения or вычитания. - В математической логике операторам
&
и|
соответствуют конъюнкция и дизъюнкция. - Логическое И похоже на умножения 1 (true) и 0 (false).
- Логическое ИЛИ напоминает поиск максимума среди 1 (true) и 0 (false).
- Для побитового отрицания целого числа a используется операция
~a
. - Для логического отрицания булевского выражения a используется операция
!a
. - Отрицательные числа хранятся и обрабатываются в дополнительном codeе.
- Поразрядный сдвиг вправо может сохранять знак (
>>
), а может — не сохранять (>>>
).
GO TO FULL VERSION